2018-05-16 23:34:34 +02:00
|
|
|
# File upload backends
|
|
|
|
|
|
|
|
Zulip in production supports a couple different backends for storing
|
|
|
|
files uploaded by users of the Zulip server (messages, profile
|
|
|
|
pictures, organization icons, custom emoji, etc.).
|
|
|
|
|
|
|
|
The default is the `LOCAL_UPLOADS_DIR` backend, which just stores
|
|
|
|
files on disk in the specified directory on the Zulip server.
|
|
|
|
Obviously, this backend doesn't work with multiple Zulip servers and
|
|
|
|
doesn't scale, but it's great for getting a Zulip server up and
|
2019-02-14 13:42:04 +01:00
|
|
|
running quickly. You can later migrate the uploads to S3 by
|
|
|
|
[following the instructions here](#migrating-from-local-uploads-to-amazon-s3-backend).
|
2018-05-16 23:34:34 +02:00
|
|
|
|
|
|
|
We also support an `S3` backend, which uses the Python `boto` library
|
2019-06-28 19:49:23 +02:00
|
|
|
to upload files to Amazon S3 (or an S3-compatible block storage
|
|
|
|
provider supported by the `boto` library).
|
2018-05-16 23:34:34 +02:00
|
|
|
|
|
|
|
## S3 backend configuration
|
|
|
|
|
|
|
|
Here, we document the process for configuring Zulip's S3 file upload
|
|
|
|
backend. To enable this backend, you need to do the following:
|
|
|
|
|
2018-05-17 16:20:07 +02:00
|
|
|
1. In the AWS management console, create a new IAM account (aka API
|
|
|
|
user) for your Zulip server, and two buckets in S3, one for uploaded
|
|
|
|
files included in messages, and another for user avatars. You need
|
|
|
|
two buckets because the "user avatars" bucket is generally configured
|
|
|
|
as world-readable, whereas the "uploaded files" one is not.
|
|
|
|
|
2018-05-16 23:34:34 +02:00
|
|
|
1. Set `s3_key` and `s3_secret_key` in /etc/zulip/zulip-secrets.conf
|
2019-06-28 19:49:23 +02:00
|
|
|
to be the S3 access and secret keys for the IAM account.
|
2018-05-16 23:34:34 +02:00
|
|
|
|
|
|
|
1. Set the `S3_AUTH_UPLOADS_BUCKET` and `S3_AVATAR_BUCKET` settings in
|
2019-06-28 19:49:23 +02:00
|
|
|
`/etc/zulip/settings.py` to be the names of the S3 buckets you
|
|
|
|
created (e.g. `exampleinc-zulip-uploads`).
|
2018-05-16 23:34:34 +02:00
|
|
|
|
|
|
|
1. Comment out the `LOCAL_UPLOADS_DIR` setting in
|
2019-06-28 19:49:23 +02:00
|
|
|
`/etc/zulip/settings.py` (add a `#` at the start of the line).
|
|
|
|
|
|
|
|
1. If you are using a non-AWS block storage provider, or certain AWS
|
|
|
|
regions, you may need to explicitly
|
|
|
|
[configure boto](http://boto.cloudhackers.com/en/latest/boto_config_tut.html).
|
|
|
|
For AWS, you may need to use AWS's SIGv4 signature format (because AWS has stopped
|
|
|
|
supporting the older v3 format in those regions); for other
|
|
|
|
providers, you may just need to set the hostname. You can do this
|
2018-12-04 22:27:33 +01:00
|
|
|
by adding an `/etc/zulip/boto.cfg` containing the following:
|
2018-11-28 21:23:57 +01:00
|
|
|
```
|
|
|
|
[s3]
|
|
|
|
use-sigv4 = True
|
2019-06-28 19:49:23 +02:00
|
|
|
# Edit to provide your bucket's AWS region or hostname here.
|
2019-02-10 19:22:34 +01:00
|
|
|
host = s3.eu-central-1.amazonaws.com
|
2018-11-28 21:23:57 +01:00
|
|
|
```
|
|
|
|
|
2019-02-10 19:22:34 +01:00
|
|
|
|
2018-05-17 16:14:18 +02:00
|
|
|
1. You will need to configure `nginx` to direct requests for uploaded
|
2018-11-28 21:19:37 +01:00
|
|
|
files to the Zulip server (which will then serve a redirect to the
|
|
|
|
appropriate place in S3), rather than serving them directly.
|
2018-05-17 16:14:18 +02:00
|
|
|
|
2018-11-28 21:19:37 +01:00
|
|
|
With Zulip 1.9.0 and newer, you can do this automatically with the
|
|
|
|
following commands run as root:
|
2018-05-17 16:14:18 +02:00
|
|
|
|
2018-11-28 21:19:37 +01:00
|
|
|
```
|
|
|
|
crudini --set /etc/zulip/zulip.conf application_server no_serve_uploads true
|
|
|
|
/home/zulip/deployments/current/scripts/zulip-puppet-apply
|
|
|
|
```
|
2018-05-17 16:14:18 +02:00
|
|
|
|
2018-11-28 21:19:37 +01:00
|
|
|
(The first line will update your `/etc/zulip/zulip.conf`).
|
2018-05-17 16:14:18 +02:00
|
|
|
|
2018-11-28 21:19:37 +01:00
|
|
|
With older Zulip, you need to edit
|
|
|
|
`/etc/nginx/sites-available/zulip-enterprise` to comment out the
|
|
|
|
`nginx` configuration block for `/user_avatars` and the `include
|
|
|
|
/etc/nginx/zulip-include/uploads.route` line and then reload the
|
|
|
|
`nginx` service (`service nginx reload`).
|
2018-05-16 23:34:34 +02:00
|
|
|
|
|
|
|
1. Finally, restart the Zulip server so that your settings changes
|
|
|
|
take effect
|
|
|
|
(`/home/zulip/deployments/current/scripts/restart-server`).
|
|
|
|
|
|
|
|
It's simplest to just do this configuration when setting up your Zulip
|
|
|
|
server for production usage. Note that if you had any existing
|
|
|
|
uploading files, this process does not upload them to Amazon S3. If
|
|
|
|
you have an existing server and are upgrading to the S3 backend, ask
|
|
|
|
in [#production help on chat.zulip.org][production-help] for advice on
|
|
|
|
how to migrate your data.
|
|
|
|
|
|
|
|
[production-help]: https://chat.zulip.org/#narrow/stream/31-production-help
|
|
|
|
|
|
|
|
## S3 bucket policy
|
|
|
|
|
|
|
|
The best way to do the S3 integration with Amazon is to create a new
|
|
|
|
IAM user just for your Zulip server with limited permissions. For
|
|
|
|
each of the two buckets, you'll want to
|
|
|
|
[add an S3 bucket policy](https://awspolicygen.s3.amazonaws.com/policygen.html)
|
|
|
|
entry that looks something like this:
|
|
|
|
|
|
|
|
```
|
|
|
|
{
|
|
|
|
"Version": "2012-10-17",
|
|
|
|
"Id": "Policy1468991802321",
|
|
|
|
"Statement": [
|
|
|
|
{
|
|
|
|
"Sid": "",
|
|
|
|
"Effect": "Allow",
|
|
|
|
"Principal": {
|
|
|
|
"AWS": "ARN_PRINCIPAL_HERE"
|
|
|
|
},
|
|
|
|
"Action": [
|
|
|
|
"s3:GetObject",
|
|
|
|
"s3:DeleteObject",
|
|
|
|
"s3:PutObject"
|
|
|
|
],
|
|
|
|
"Resource": "arn:aws:s3:::BUCKET_NAME_HERE/*"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"Sid": "Stmt1468991795389",
|
|
|
|
"Effect": "Allow",
|
|
|
|
"Principal": {
|
|
|
|
"AWS": "ARN_PRINCIPAL_HERE"
|
|
|
|
},
|
|
|
|
"Action": "s3:ListBucket",
|
|
|
|
"Resource": "arn:aws:s3:::BUCKET_NAME_HERE"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
The avatars bucket is intended to be world-readable, so you'll also
|
|
|
|
need a block like this:
|
|
|
|
|
|
|
|
```
|
|
|
|
{
|
|
|
|
"Sid": "Stmt1468991795389",
|
|
|
|
"Effect": "Allow",
|
|
|
|
"Principal": {
|
|
|
|
"AWS": "*"
|
|
|
|
},
|
|
|
|
"Action": "s3:GetObject",
|
|
|
|
"Resource": "arn:aws:s3:::BUCKET_NAME_HERE/*"
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
The file-uploads bucket should not be world-readable. See the
|
2019-09-30 19:37:56 +02:00
|
|
|
[documentation on the Zulip security model](security-model.md) for
|
2018-05-16 23:34:34 +02:00
|
|
|
details on the security model for uploaded files.
|
2019-02-14 13:42:04 +01:00
|
|
|
|
|
|
|
## Migrating from local uploads to Amazon S3 backend
|
|
|
|
|
|
|
|
As you scale your server, you might want to migrate the uploads from
|
|
|
|
your local backend to Amazon S3. Follow these instructions, step by
|
|
|
|
step, to do the migration.
|
|
|
|
|
|
|
|
1. First, [setup the S3 backend](#s3-backend-configuration) in the settings
|
|
|
|
(all the auth stuff), but leave `LOCAL_UPLOADS_DIR` set -- the
|
|
|
|
migration tool will need that value to know where to find your uploads.
|
|
|
|
2. Run `./manage.py transfer_uploads_to_s3`. This will upload all the
|
|
|
|
files from the local uploads directory to Amazon S3. By default,
|
|
|
|
this command runs on 6 parallel processes, since uploading is a
|
|
|
|
latency-sensitive operation. You can control this parameter using
|
|
|
|
the `--processes` option.
|
|
|
|
3. Once the transer script compltes, disable `LOCAL_UPLOADS_DIR`, and
|
|
|
|
restart your server (continuing the last few steps of the S3
|
|
|
|
backend setup instructions).
|
|
|
|
|
|
|
|
Congratulations! Your uploaded files are now migrated to S3.
|
|
|
|
|
|
|
|
**Caveat**: The current version of this tool does not migrate an
|
|
|
|
uploaded organization avatar or logo.
|