2020-08-11 01:47:54 +02:00
|
|
|
# Installing SSL certificates
|
2017-11-18 12:56:32 +01:00
|
|
|
|
2017-11-16 04:44:52 +01:00
|
|
|
To keep your communications secure, Zulip runs over HTTPS only.
|
2017-10-28 02:46:31 +02:00
|
|
|
You'll need an SSL/TLS certificate.
|
|
|
|
|
2018-01-23 20:08:17 +01:00
|
|
|
Fortunately, since about 2017, new options can make getting and
|
|
|
|
maintaining a genuine, trusted-by-browsers certificate no longer the
|
|
|
|
chore (nor expense) that it used to be.
|
2017-10-28 02:46:31 +02:00
|
|
|
|
|
|
|
## Manual install
|
|
|
|
|
2017-12-13 04:49:21 +01:00
|
|
|
If you already have an SSL certificate, just install (or symlink) its
|
|
|
|
files into place at the following paths:
|
2021-08-20 22:54:08 +02:00
|
|
|
|
2021-08-20 21:45:39 +02:00
|
|
|
- `/etc/ssl/private/zulip.key` for the private key
|
|
|
|
- `/etc/ssl/certs/zulip.combined-chain.crt` for the certificate.
|
2017-12-13 04:49:21 +01:00
|
|
|
|
2018-04-16 20:29:19 +02:00
|
|
|
Your certificate file should contain not only your own certificate but
|
2018-10-04 01:00:59 +02:00
|
|
|
its **full chain, including any intermediate certificates** used by
|
2021-08-20 21:53:28 +02:00
|
|
|
your certificate authority (CA). See the [nginx
|
|
|
|
documentation][nginx-chains] for details on what this means. If
|
2019-08-19 23:21:06 +02:00
|
|
|
you're missing part of the chain, your server may work with some
|
|
|
|
browsers, but not others and not the Zulip mobile and desktop apps.
|
|
|
|
The desktop apps support [configuring a custom CA][desktop-certs] to
|
|
|
|
allow validation of certificates generated by an internal CA.
|
2018-04-16 20:29:19 +02:00
|
|
|
|
2020-03-27 01:32:21 +01:00
|
|
|
[nginx-chains]: https://nginx.org/en/docs/http/configuring_https_servers.html#chains
|
2017-11-16 04:44:52 +01:00
|
|
|
|
2018-10-04 01:00:59 +02:00
|
|
|
### Testing
|
|
|
|
|
|
|
|
Just trying in a browser is not an adequate test, because some
|
|
|
|
browsers ignore errors that others don't.
|
|
|
|
|
|
|
|
Two good tests include:
|
|
|
|
|
2021-08-20 21:45:39 +02:00
|
|
|
- If your server is accessible from the public Internet, use the [SSL
|
2021-08-20 21:53:28 +02:00
|
|
|
Labs tester][ssllabs-tester]. Be sure to check for "Chain issues";
|
2018-10-04 01:00:59 +02:00
|
|
|
if any, your certificate file is missing intermediate certificates.
|
|
|
|
|
2021-08-20 21:45:39 +02:00
|
|
|
- Alternatively, run a command like `curl -SsI https://zulip.example.com`
|
2018-10-04 01:00:59 +02:00
|
|
|
(using your server's URL) from a machine that can reach your server.
|
2021-09-08 00:23:24 +02:00
|
|
|
Make sure that on the same machine,
|
|
|
|
`curl -SsI https://incomplete-chain.badssl.com` gives an error;
|
|
|
|
`curl` on some machines, including Macs, will accept incomplete
|
|
|
|
chains.
|
2018-10-04 01:00:59 +02:00
|
|
|
|
|
|
|
[ssllabs-tester]: https://www.ssllabs.com/ssltest/analyze.html
|
|
|
|
|
2017-12-13 04:50:51 +01:00
|
|
|
## Certbot (recommended)
|
2017-11-16 04:44:52 +01:00
|
|
|
|
|
|
|
[Let's Encrypt](https://letsencrypt.org/) is a free, completely
|
|
|
|
automated CA launched in 2016 to help make HTTPS routine for the
|
2021-08-20 21:53:28 +02:00
|
|
|
entire Web. Zulip offers a simple automation for
|
2017-11-16 04:44:52 +01:00
|
|
|
[Certbot](https://certbot.eff.org/), a Let's Encrypt client, to get
|
|
|
|
SSL certificates from Let's Encrypt and renew them automatically.
|
|
|
|
|
2021-08-20 21:53:28 +02:00
|
|
|
We recommend most Zulip servers use Certbot. You'll want something
|
2017-11-16 04:44:52 +01:00
|
|
|
else if:
|
2021-08-20 22:54:08 +02:00
|
|
|
|
2021-08-20 21:45:39 +02:00
|
|
|
- you have an existing workflow for managing SSL certificates
|
2017-11-16 04:44:52 +01:00
|
|
|
that you prefer;
|
2021-08-20 21:45:39 +02:00
|
|
|
- you need wildcard certificates (support from Let's Encrypt released
|
2021-01-17 09:43:04 +01:00
|
|
|
in [March 2018][letsencrypt-wildcard]); or
|
2021-08-20 21:45:39 +02:00
|
|
|
- your Zulip server is not on the public Internet. (In this case you
|
2017-11-16 04:44:52 +01:00
|
|
|
can [still use Certbot][certbot-manual-mode], but it's less
|
|
|
|
convenient; and you'll want to ignore Zulip's automation.)
|
|
|
|
|
2021-01-17 09:43:04 +01:00
|
|
|
[letsencrypt-wildcard]: https://certbot.eff.org/faq#does-let-s-encrypt-issue-wildcard-certificates
|
2017-11-16 04:44:52 +01:00
|
|
|
[certbot-manual-mode]: https://certbot.eff.org/docs/using.html#manual
|
|
|
|
|
|
|
|
### At initial Zulip install
|
|
|
|
|
|
|
|
To enable the Certbot automation when first installing Zulip, just
|
2017-12-13 05:13:34 +01:00
|
|
|
pass the `--certbot` flag when [running the install script][doc-install-script].
|
2017-11-16 04:44:52 +01:00
|
|
|
|
|
|
|
The `--hostname` and `--email` options are required when using
|
2021-08-20 21:53:28 +02:00
|
|
|
`--certbot`. You'll need the hostname to be a real DNS name, and the
|
2017-11-16 04:44:52 +01:00
|
|
|
Zulip server machine to be reachable by that name from the public
|
|
|
|
Internet.
|
|
|
|
|
2018-10-20 10:11:46 +02:00
|
|
|
If you need to configure a multiple domain certificate, you can generate
|
|
|
|
one as described in the section below after installing Zulip.
|
|
|
|
|
2022-02-16 01:39:15 +01:00
|
|
|
[doc-install-script]: install.md#step-2-install-zulip
|
2017-12-13 05:13:34 +01:00
|
|
|
|
2017-11-16 04:44:52 +01:00
|
|
|
### After Zulip is already installed
|
|
|
|
|
|
|
|
To enable the Certbot automation on an already-installed Zulip
|
|
|
|
server, run the following commands:
|
2021-08-20 22:54:08 +02:00
|
|
|
|
2021-08-20 07:09:04 +02:00
|
|
|
```bash
|
2017-11-16 04:44:52 +01:00
|
|
|
sudo -s # If not already root
|
2018-10-20 10:11:46 +02:00
|
|
|
/home/zulip/deployments/current/scripts/setup/setup-certbot --email=EMAIL HOSTNAME [HOSTNAME2...]
|
2016-08-25 06:33:09 +02:00
|
|
|
```
|
2021-08-20 22:54:08 +02:00
|
|
|
|
2017-11-16 04:44:52 +01:00
|
|
|
where HOSTNAME is the domain name users see in their browser when
|
|
|
|
using the server (e.g., `zulip.example.com`), and EMAIL is a contact
|
2018-10-20 10:11:46 +02:00
|
|
|
address for the server admins. Additional hostnames can also be
|
|
|
|
specified to issue a certificate for multiple domains.
|
2016-08-25 06:33:09 +02:00
|
|
|
|
2017-11-16 04:44:52 +01:00
|
|
|
### How it works
|
2016-08-25 06:33:09 +02:00
|
|
|
|
2017-11-16 04:44:52 +01:00
|
|
|
When the Certbot automation in Zulip is first enabled, by either
|
|
|
|
method, it creates an account for the server at the Let's Encrypt CA;
|
|
|
|
requests a certificate for the given hostname; proves to the CA that
|
|
|
|
the server controls the website at that hostname; and is then given a
|
2021-08-20 21:53:28 +02:00
|
|
|
certificate. (For details, refer to
|
2017-11-16 04:44:52 +01:00
|
|
|
[Let's Encrypt](https://letsencrypt.org/how-it-works/).)
|
2016-08-25 06:33:09 +02:00
|
|
|
|
2021-11-01 19:31:40 +01:00
|
|
|
### Renewal
|
|
|
|
|
|
|
|
Let's Encrypt certificates expire after 90 days. Short expiration
|
|
|
|
periods are good for security, but they also mean that it's important
|
|
|
|
to automatically renew them to avoid regular maintenance work.
|
|
|
|
|
|
|
|
Zulip configures automatic renewal for you. As a result, a Zulip
|
|
|
|
server configured with Certbot does not require any ongoing work to
|
|
|
|
maintain a current valid SSL certificate.
|
|
|
|
|
puppet: Use certbot package timer, not our own cron job.
The certbot package installs its own systemd timer (and cron job,
which disabled itself if systemd is enabled) which updates
certificates. This process races with the cron job which Zulip
installs -- the only difference being that Zulip respects the
`certbot.auto_renew` setting, and that it passes the deploy hook.
This means that occasionally nginx would not be reloaded, when the
systemd timer caught the expiration first.
Remove the custom cron job and `certbot-maybe-renew` script, and
reconfigure certbot to always reload nginx after deploying, using
certbot directory hooks.
Since `certbot.auto_renew` can't have an effect, remove the setting.
In turn, this removes the need for `--no-zulip-conf` to
`setup-certbot`. `--deploy-hook` is similarly removed, as running
deploy hooks to restart nginx is now the default; pass
`--no-directory-hooks` in standalone mode to not attempt to reload
nginx. The other property of `--deploy-hook`, of skipping symlinking
into place, is given its own flog.
2021-12-08 23:44:33 +01:00
|
|
|
The `certbot` package configures a systemd timer (similar to a cron
|
|
|
|
job) that will renew any Certbot certificates that are due for
|
|
|
|
renewal. The renewal process repeats the Certbot proof-of-control
|
|
|
|
process, receives the new certificate from Certbot, installs the new
|
|
|
|
certificate, and then reloads `nginx`.
|
2021-11-01 19:31:40 +01:00
|
|
|
|
|
|
|
#### Troubleshooting
|
|
|
|
|
|
|
|
If your Certbot certificate expires, it is usually because of firewall
|
|
|
|
rules preventing the Certbot renewal process (which is essentially
|
|
|
|
identical to the initial certificate request process) from
|
|
|
|
working. You can debug interactively by running the command from the
|
puppet: Use certbot package timer, not our own cron job.
The certbot package installs its own systemd timer (and cron job,
which disabled itself if systemd is enabled) which updates
certificates. This process races with the cron job which Zulip
installs -- the only difference being that Zulip respects the
`certbot.auto_renew` setting, and that it passes the deploy hook.
This means that occasionally nginx would not be reloaded, when the
systemd timer caught the expiration first.
Remove the custom cron job and `certbot-maybe-renew` script, and
reconfigure certbot to always reload nginx after deploying, using
certbot directory hooks.
Since `certbot.auto_renew` can't have an effect, remove the setting.
In turn, this removes the need for `--no-zulip-conf` to
`setup-certbot`. `--deploy-hook` is similarly removed, as running
deploy hooks to restart nginx is now the default; pass
`--no-directory-hooks` in standalone mode to not attempt to reload
nginx. The other property of `--deploy-hook`, of skipping symlinking
into place, is given its own flog.
2021-12-08 23:44:33 +01:00
|
|
|
cron job, `/usr/bin/certbot renew`, as `root`.
|
2016-08-25 06:33:09 +02:00
|
|
|
|
2017-12-13 04:50:51 +01:00
|
|
|
## Self-signed certificate
|
2016-08-25 06:33:09 +02:00
|
|
|
|
2019-08-19 23:21:06 +02:00
|
|
|
If you aren't able to use Certbot, you can generate a self-signed SSL
|
2021-08-20 21:53:28 +02:00
|
|
|
certificate. This can be convenient for testing, but isn't
|
|
|
|
recommended for production, as it is insecure. The Zulip desktop and
|
2019-08-19 23:21:06 +02:00
|
|
|
mobile apps will not connect to a server if they cannot validate its
|
2021-08-20 21:53:28 +02:00
|
|
|
SSL certificate. The desktop apps support [configuring a custom
|
2019-08-19 23:21:06 +02:00
|
|
|
certificate authority][desktop-certs] to allow validation of an
|
|
|
|
internal certificate.
|
2016-08-25 06:33:09 +02:00
|
|
|
|
2018-01-24 02:54:23 +01:00
|
|
|
To generate a self-signed certificate when first installing Zulip,
|
|
|
|
just pass the `--self-signed-cert` flag when
|
|
|
|
[running the install script][doc-install-script].
|
2016-08-25 06:33:09 +02:00
|
|
|
|
2018-01-24 02:54:23 +01:00
|
|
|
To generate a self-signed certificate for an already-installed Zulip
|
|
|
|
server, run the following commands:
|
2021-08-20 22:54:08 +02:00
|
|
|
|
2021-08-20 07:09:04 +02:00
|
|
|
```bash
|
2018-01-24 02:54:23 +01:00
|
|
|
sudo -s # If not already root
|
|
|
|
/home/zulip/deployments/current/scripts/setup/generate-self-signed-cert HOSTNAME
|
2016-08-25 06:33:09 +02:00
|
|
|
```
|
2021-08-20 22:54:08 +02:00
|
|
|
|
2018-01-24 02:54:23 +01:00
|
|
|
where HOSTNAME is the domain name (or IP address) to use on the
|
|
|
|
generated certificate.
|
2018-12-25 11:39:15 +01:00
|
|
|
|
|
|
|
After replacing the certificates, you need to reload `nginx` by
|
|
|
|
running the following as `root`:
|
2021-08-20 22:54:08 +02:00
|
|
|
|
2021-08-20 07:09:04 +02:00
|
|
|
```bash
|
2018-12-25 11:39:15 +01:00
|
|
|
service nginx reload
|
|
|
|
```
|
2019-08-19 23:21:06 +02:00
|
|
|
|
2020-06-08 23:04:39 +02:00
|
|
|
[desktop-certs]: https://zulip.com/help/custom-certificates
|
2019-08-26 22:03:00 +02:00
|
|
|
|
|
|
|
## Troubleshooting
|
|
|
|
|
|
|
|
### The Android app can't connect to the server
|
|
|
|
|
2021-08-20 21:53:28 +02:00
|
|
|
This is most often caused by an incomplete certificate chain. See
|
2019-08-26 22:03:00 +02:00
|
|
|
discussion in the [Manual install](#manual-install) section above.
|
|
|
|
|
2019-08-28 01:24:54 +02:00
|
|
|
### The iOS app can't connect to the server
|
|
|
|
|
|
|
|
This can be caused by a server set up to support only TLS 1.1 or
|
|
|
|
older (including TLS 1.0, SSL 3, or SSL 2.)
|
|
|
|
|
|
|
|
TLS 1.2 has been a standard for over 10 years, and all modern web
|
2021-08-20 21:53:28 +02:00
|
|
|
server software supports it. Starting in early 2020, all major
|
2021-08-20 22:54:08 +02:00
|
|
|
browsers [will _require_ TLS 1.2 or later][tls12-required-news], and
|
2021-08-20 21:53:28 +02:00
|
|
|
will refuse to connect over TLS 1.1 or older. And on iOS, Apple [has
|
2019-08-28 01:24:54 +02:00
|
|
|
since iOS 9][apple-ats] required TLS 1.2 for all connections made by
|
|
|
|
apps, unless the app specifically opts into lower security.
|
|
|
|
|
|
|
|
[tls12-required-news]: https://www.thesslstore.com/blog/apple-microsoft-google-disable-tls-1-0-tls-1-1/
|
|
|
|
[apple-ats]: https://developer.apple.com/library/archive/releasenotes/General/WhatsNewIniOS/Articles/iOS9.html
|
|
|
|
|
|
|
|
If your server is reachable from the public Internet, a convenient way
|
|
|
|
to check what TLS versions it supports is the [SSL Labs
|
|
|
|
tester][ssllabs-tester].
|
|
|
|
|
|
|
|
To resolve this issue, update your server to support TLS 1.2,
|
2021-08-20 21:53:28 +02:00
|
|
|
and preferably also TLS 1.3. For nginx, see [the `ssl_protocols`
|
2019-08-28 01:24:54 +02:00
|
|
|
directive][nginx-doc-protocols] in your configuration.
|
|
|
|
|
2020-03-27 01:32:21 +01:00
|
|
|
[nginx-doc-protocols]: https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_protocols
|
2019-08-28 01:24:54 +02:00
|
|
|
|
2019-08-26 22:03:00 +02:00
|
|
|
### The Android app connects to the server on some devices but not others
|
|
|
|
|
|
|
|
An issue on Android 7.0 ([report][android7.0-tls-issue],
|
|
|
|
[description][android7.0-tls-issue-so]) in the system TLS/SSL stack,
|
|
|
|
which the Zulip app relies on, makes it finicky about the server's TLS
|
|
|
|
configuration.
|
|
|
|
|
|
|
|
[android7.0-tls-issue]: https://issuetracker.google.com/issues/37122132#comment13
|
2019-08-26 22:42:19 +02:00
|
|
|
[android7.0-tls-issue-so]: https://stackoverflow.com/a/42047877
|
2019-08-26 22:03:00 +02:00
|
|
|
|
|
|
|
The issue is that Android 7.0 supports only the curve `secp256r1` when
|
|
|
|
doing elliptic-curve cryptography for TLS, and not other curves like
|
2021-08-20 21:53:28 +02:00
|
|
|
`secp384r1` or `secp512r1`. If your server's TLS/SSL configuration
|
2019-08-26 22:03:00 +02:00
|
|
|
offers only other curves, then Android 7.0 clients will be unable to
|
|
|
|
connect.
|
|
|
|
|
|
|
|
By default `nginx` (and therefore a Zulip server) offers the
|
2021-08-20 21:53:28 +02:00
|
|
|
`secp256r1` curve among others, and so everything works. You can
|
2019-08-26 22:03:00 +02:00
|
|
|
control the offered curves with `ssl_ecdh_curve` in the `nginx`
|
2021-08-20 21:53:28 +02:00
|
|
|
configuration on your server. See [nginx docs][nginx-doc-curve] for
|
2019-08-26 22:03:00 +02:00
|
|
|
details.
|
|
|
|
|
2020-03-27 01:32:21 +01:00
|
|
|
[nginx-doc-curve]: https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_ecdh_curve
|
2019-08-26 22:03:00 +02:00
|
|
|
|
|
|
|
Two signs for diagnosing this issue in contrast to some other root
|
|
|
|
cause:
|
|
|
|
|
2021-08-20 21:45:39 +02:00
|
|
|
- This issue affects only Android 7.0; it's fixed in Android 7.1.1 and
|
2019-08-26 22:03:00 +02:00
|
|
|
later.
|
|
|
|
|
2021-08-20 21:45:39 +02:00
|
|
|
- If your server is reachable from the public Internet, use the [SSL
|
2021-08-20 21:53:28 +02:00
|
|
|
Labs tester][ssllabs-tester]. Under "Cipher Suites" you may see
|
2019-08-26 22:03:00 +02:00
|
|
|
lines beginning with `TLS_ECDHE`, for cipher suites which use
|
2021-08-20 21:53:28 +02:00
|
|
|
elliptic-curve cryptography. These lines will have further text
|
2019-08-26 22:03:00 +02:00
|
|
|
like `ECDH secp256r1` or `ECDH secp384r1`, which identifies specific
|
2021-08-20 21:53:28 +02:00
|
|
|
elliptic curves your server offers to use. This issue applies if
|
2019-08-26 22:03:00 +02:00
|
|
|
your server does not offer `secp256r1`.
|