@@ -1,5 +1,5 @@
11+++
2−title = "Self-hosting S3 Storage"
2+title = "Self-hosting S3 Storage with MinIO"
33description = "How to set up and self-host MinIO S3 storage"
44template = "doc.html"
55weight = 2
@@ -7,7 +7,7 @@ weight = 2
77hidetitle = "true"
88+++
99
10−Adding [S3](https://aws.amazon.com/s3/) storage to Urbit unlocks some great new features, such as the ability to post media to chats and upload custom avatars. This is a guide to self-hosting [MinIO](https://min.io), an S3 compatible block storage solution.
10+Adding [S3](https://aws.amazon.com/s3/) storage to Urbit unlocks some great new features, such as the ability to upload & post your own media to chats straight from your own machine, and upload custom avatars. This is a guide to self-hosting [MinIO](https://min.io), an S3 compatible block storage solution.
1111
1212You can read more about S3 in [Configuring S3 Storage](/using/os/s3).
1313
@@ -39,110 +39,76 @@ Once Docker is installed, we can install and run MinIO by following the steps [h
3939You should only need to run a single command, along the lines of:
4040
4141```
42−docker run -d -p 9000:9000 \
42+docker run -d \
43+ -p 9000:9000 \
44+ -p 9001:9001 \
4345 --name minio-urbit \
4446 -v /mnt/data:/data \
45− -e "MINIO_ACCESS_KEY=<access_key>" \
46− -e "MINIO_SECRET_KEY=<secret_key>" \
47− -e "MINIO_DOMAIN=s3.example.com" \
48− minio/minio server /data
47+ -e "MINIO_ROOT_USER=<username>" \
48+ -e "MINIO_ROOT_PASSWORD=<password>" \
49+ -e "MINIO_DOMAIN=example.com" \
50+ minio/minio server /data --console-address ":9001"
4951```
5052
51−`/mnt/data` is the path where your uploaded data will be stored on your host machine - you can change this as necessary.
53+Ports 9000 and 9001 are exposed to give access to the MinIO admin interface and MinIO S3 admin respectively. `/mnt/data` is the path where your uploaded data will be stored on your host machine — you can change this as necessary.
5254
53−Be sure to add the `MINIO_DOMAIN` environment variable; this tells MinIO to accept virtual host style URLs (`BUCKET.s3.example.com` rather than `s3.example.com/BUCKET`), which are required for compatibility with Urbit.
55+Be sure to add the `MINIO_DOMAIN` environment variable; this tells MinIO to accept virtual host style URLs (`BUCKET.example.com` rather than `example.com/BUCKET`), which are required for compatibility with Urbit.
5456
55−Your access key and secret key can be anything of your choosing — make sure they're secure! ~ribben-donnyl recommended a handy tool called [minio-keygen](https://github.com/iwittkau/minio-keygen) that will generate secure keys for you. You could also use your `@p` and `+code` for an easy to remember solution.
57+Your username and password can be anything of your choosing — make sure they're secure! You could use your `@p` and `+code` for an easy to remember solution, or even just generate some random alphanumeric strings using a Unix tool, e.g.
58+
59+```
60+tr -dc A-Z0-9 </dev/urandom | head -c 24 ; echo ''
61+```
5662
5763### Create DNS records
5864
5965Now, you'll need to point your own domain at your MinIO installation. Via your domain's DNS settings (usually configured on the registrar you bought your domain through), create two `A` records:
6066
61−- `s3`.example.com, and
62−- `*.s3`.example.com
63−
64−Both should point at the IP address of your host machine. If you are hosting on your own hardware, this could require port-forwarding via your router so that your host machine is reachable from outside of your home network.
67+- `s3.example.com`, and
68+- `BUCKET.example.com` where BUCKET is a bucket name of your choosing — 'media' or 'uploads' are good examples
6569
66−It's important that you create both records — without the wildcard, you'll be able to access your S3 web interface but not upload/download content from any buckets you create.
70+Both should point at the IP address of your host machine. If you are hosting on your own hardware, this could require port-forwarding via your router so that your host machine is reachable from outside of your home network, and possibly using a dynamic DNS service to update your DNS records if your home IP is not static.
6771
6872DNS records can take a little while to propagate, so don't worry if you type your new URL into your browser and don't see anything yet.
6973
70−### Configure a TLS certificate
74+_Note: if you plan to create multiple buckets, you will need a DNS record for each. Alternatively you can use a wildcard domain record, but for use with Urbit only one bucket is needed._
7175
72−Next, you need to aquire a TLS certificate from Let's Encrypt. TLS ensures that all traffic to and from your S3 installation is encrypted, and is required for your installation to work with Urbit.
76+### Set up the reverse proxy
7377
74−The EFF Certbot tool is the easiest way to get a certificate, and [this page](https://certbot.eff.org/instructions) will tell you how to install it depending on your requirements. Select **NGINX** and your operating system for the correct guide.
75−
76−Once Certbot is installed, you can generate a certificate with the following command:
77−
78−```
79−sudo certbot --server https://acme-v02.api.letsencrypt.org/directory \
80− -d *.s3.example.com \
81− -d s3.example.com \
82− --manual --preferred-challenges dns-01 certonly
83−```
78+Setting up a reverse proxy in front of MinIO allows us to configure domain names and TLS. In this guide we use caddy, an incredibly simple web server. If you have experience with other web servers, you are also able to use those in place of caddy.
8479
85−After answering a few questions, you will be prompted with a DNS challenge to prove that you own the domains you are creating certificates for. After successfully completing the DNS challenge, your certificate files will be generated and Certbot will print the paths at which they are located. Take note of these for the next step.
80+To install caddy, follow the instructions [here](https://caddyserver.com/docs/install).
8681
87−Let's Encrypt certificates expire after 90 days, so don't forget to renew them. You should receive an email (to the address you entered when creating the certs) before they are due to expire. To renew, simply repeat the process listed above.
88−
89−### Install NGINX
90−
91−Install the NGINX web server and place the following config file at `/etc/nginx/sites-enabled/s3.example.com`. NGINX will act as a proxy to MinIO, allowing us to use our domain and enable TLS.
82+Caddy handles TLS automatically, so we don't need to worry about setting that up. All we need to do is create a Caddyfile that looks something like this:
9283
9384```
94−server {
95− listen 443 ssl;
96− server_name *.s3.example.com;
97−
98− ignore_invalid_headers off;
99− client_max_body_size 0;
100− proxy_buffering off;
101−
102− ssl_certificate /etc/letsencrypt/live/s3.example.com/fullchain.pem;
103− ssl_certificate_key /etc/letsencrypt/live/s3.example.com/privkey.pem;
104− include /etc/letsencrypt/options-ssl-nginx.conf;
105− ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
106−
107− location / {
108− proxy_set_header X-Real-IP $remote_addr;
109− proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
110− proxy_set_header X-Forwarded-Proto $scheme;
111− proxy_set_header Host $http_host;
112−
113− proxy_pass http://localhost:9000;
114− }
85+s3.example.com {
86+ reverse_proxy localhost:9001 {
87+ header_up X-Forwarded-Host {host}
88+ header_up Host {host}
89+ }
11590}
116−
117−server {
118− listen 80;
119− server_name *.s3.example.com;
120−
121− if ($host = *.s3.example.com) {
122− return 301 https://$host$request_uri;
123− }
124−
125− return 404;
91+BUCKET.example.com {
92+ reverse_proxy localhost:9000 {
93+ header_up X-Forwarded-Host {host}
94+ header_up Host {host}
95+ }
12696}
12797```
12898
129−Update your `server_name` values, ensure that the paths to your certificate files are correct, and change your `proxy_pass` value if you are running MinIO on a different port.
130−
131−You can test your configuration with `nginx -t`. Any errors will be printed so that you can rectify them.
132−
133−Restart NGINX to apply the new configuration.
99+Remember to replace BUCKET with your chosen bucket name, and then run `caddy start` in the same directory as the Caddyfile.
134100
135101### Create an S3 bucket
136102
137−Navigate to your root MinIO endpoint (`https://s3.example.com`) in a browser and sign in using the access key and secret key you entered in step 1.
103+Navigate to your MinIO admin endpoint (`https://s3.example.com`) in a browser and sign in using the username and password you entered in step 1.
138104
139−Create a new bucket with the plus button in the bottom right-hand corner of the interface. In the list of buckets on the left hand side of the interface, you should see an option to change the policy to read/write.
105+Choose 'buckets' from the left-hand menu, and then 'create bucket' at the top of the page. Enter your bucket name (this MUST match the name in your DNS record, e.g. 'media').
140106
141107### Configure your ship
142108
143−Head over to Landscape and enter your root MinIO endpoint (with protocol) in the S3 settings, e.g. `https://s3.example.com`. Enter your access key and secret, and then enter the name of the bucket you created in the previous step.
109+Head over to Landscape and navigate to the S3 storage setup page at System preferences > Remote Storage, and enter your domain (with protocol) under endpoint, e.g. `https://example.com`. Enter your username and password from step 1 under access key and secret, and then enter the name of the bucket. When the bucket name is combined with the endpoint, you get your bucket URL e.g. `https://media.example.com`.
144110
145−You can also configure these settings through Dojo as shown [here](/using/os/s3).
111+You can also configure these settings through dojo as shown [here](/using/os/s3).
146112
147113### That's it!
148114
@@ -153,24 +119,25 @@ You should now be able to upload content using your self-hosted MinIO installati
153119Landscape chat will fail silently if it cannot connect to your S3 endpoint to upload media. To get an idea of what's going wrong, open the network tab of your browser dev tools, and observe the request when you try and upload media. You should see a failed request, hopefully with an error code or reason for failure.
154120
155121- If you see a `mixed-content` error, this means that not every part of the set up is using TLS. Most browsers will refuse to load non-HTTPS content from a secure page.
156−- If you see a `502 Bad Gateway` error, NGINX is unable to reach your MinIO installation. Check MinIO is running and your `proxy_pass` URL is correct.
157−- If you get a `Permission denied` error, it's likely that your bucket endpoint is incorrect. Ensure your NGINX config includes the `proxy_set_header` options, and that you passed the `MINIO_DOMAIN` variable when running MinIO - otherwise it will default to using the path URL format, which Urbit does not support.
122+- If you see a `502 Bad Gateway` error, caddy is unable to reach your MinIO installation. Check MinIO is running and your `reverse_proxy` URLs are correct.
123+- If you get a `Permission denied` error, it's likely that your bucket endpoint is incorrect. Ensure your Caddyfile includes the `header_up` options, and that you passed the `MINIO_DOMAIN` variable when running MinIO - otherwise it will default to using the path URL format, which Urbit does not support.
158124
159125A good way to test your setup is to `curl` your S3 bucket endpoint (not your root S3 endpoint) and see what response you get. For example, if we have a bucket named 'media':
160126
161127```
162−curl https://media.s3.example.com
128+curl https://media.example.com
163129```
164130
165131You should get an XML response listing the contents of your bucket.
166132
167133## Running MinIO and Urbit on the same machine
168134
169−You may wonder how it's possible to run Urbit alongside our MinIO/NGINX set up if they both need ports 80/443. The answer is to proxy Urbit through NGINX, exactly the same way as MinIO. You can create as many config files in `/etc/nginx/sites-enabled` as you need, and NGINX will direct requests to the relevant one by comparing `server_name` values.
135+You may wonder how it's possible to run Urbit alongside our MinIO set up if they both need ports 80/443. The answer is to proxy Urbit through caddy, exactly the same way as MinIO. You can create as many directives in your Caddyfile as needed, each pointing to a different port.
170136
171−For example, you could have 2 domains pointing to 2 separate NGINX configs:
137+For example, you could have 3 domains:
172138
173−- `ship-name.example.com` - proxy to port 8080 where Urbit is running, and
174−- `s3.example.com` - proxy to port 9000 where MinIO is running
139+- `ship-name.example.com` - proxy to port 8080 where Urbit is running,
140+- `s3.example.com` - proxy to port 9001 where your MinIO admin is running, and
141+- `media.example.com` - proxy to port 9000 where your MinIO bucket is accessible
175142
176−Currently, there is no way to specify the HTTP port Landscape runs on, but if 80 is not available at start-up it will try 8080 next. So start NGINX first, and when you boot your ship it should detect that port 80 is in use and use 8080 instead.
143+Currently, there is no way to specify the HTTP port Landscape runs on, but if 80 is not available at start-up it will try 8080 next. So start caddy first, and when you boot your ship it should detect that port 80 is in use and use 8080 instead.