Skip to content

Commit

Permalink
Documentation: full deployment example in AWS with Ubuntu 20.04
Browse files Browse the repository at this point in the history
  • Loading branch information
David Dumas authored and timvisee committed May 19, 2021
1 parent 72377d3 commit dc816d0
Show file tree
Hide file tree
Showing 5 changed files with 299 additions and 32 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
node_modules
coverage
dist
.env
.idea
.DS_Store
.nyc_output
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTORS
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Cynthia Pereira
Daniel Thorn
Daniela Arcese
Danny Coates
David Dumas
Davide
Derek Tamsen
Dhyey Thakore
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ A file sharing experiment which allows you to send encrypted files to other user

## Requirements

- [Node.js 12.x](https://nodejs.org/)
- [Node.js 15.x](https://nodejs.org/)
- [Redis server](https://redis.io/) (optional for development)
- [AWS S3](https://aws.amazon.com/s3/) or compatible service (optional)

Expand Down Expand Up @@ -141,6 +141,8 @@ Find a list of public instances here: https://github.com/timvisee/send-instances

See also [docs/deployment.md](docs/deployment.md)

AWS example using Ubuntu Server `20.04` [docs/AWS.md](docs/AWS.md)

---

## Clients
Expand Down
236 changes: 236 additions & 0 deletions docs/AWS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
# Deployment to AWS

This document describes how to do a deployment of Send in AWS

## AWS requirements

### Security groups (2)

* ALB:
- inbound: allow traffic from anywhere on port 80 and 443
- ountbound: allow traffic to the instance security group on port `8080`

* Instance:
- inbound: allow SSH from your public IP or a bastion (changing the default SSH port is a good idea)
- inbound: allow traffic from the ALB security group on port `8080`
- ountbound: allow all traffic to anywhere

### Resources

* An S3 bucket (block all public access)

* A private EC2 instance running Ubuntu `20.04` (you can use the [Amazon EC2 AMI Locator](https://cloud-images.ubuntu.com/locator/ec2/) to find the latest)

Attach an IAM role to the instance with the following inline policy:

```json
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:ListAllMyBuckets"
],
"Resource": [
"*"
],
"Effect": "Allow"
},
{
"Action": [
"s3:ListBucket",
"s3:GetBucketLocation",
"s3:ListBucketMultipartUploads"
],
"Resource": [
"arn:aws:s3:::<s3_bucket_name>"
],
"Effect": "Allow"
},
{
"Action": [
"s3:GetObject",
"s3:GetObjectVersion",
"s3:ListMultipartUploadParts",
"s3:PutObject",
"s3:AbortMultipartUpload",
"s3:DeleteObject",
"s3:DeleteObjectVersion"
],
"Resource": [
"arn:aws:s3:::<s3_bucket_name>/*"
],
"Effect": "Allow"
}
]
}
```

* A public ALB:

- Create a target group with the instance registered (HTTP on port `8080` and path `/`)
- Configure HTTP (port 80) to redirect to HTTPS (port 443)
- HTTPS (port 443) using the latest security policy and an ACM certificate like `send.mydomain.com`

* A Route53 public record, alias from `send.mydomain.com` to the ALB

## Software requirements

* Git
* NodeJS `15.x` LTS
* Local Redis server

### Prerequisite packages

```bash
sudo apt update
sudo apt install -y apt-transport-https ca-certificates curl software-properties-common
```

### Add repositories

* NodeJS `15.x` LTS (checkout [package.json](../package.json)):

```bash
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | sudo apt-key add -
echo 'deb [arch=amd64] https://deb.nodesource.com/node_15.x focal main' | sudo tee /etc/apt/sources.list.d/nodejs.list
```

* Git (latest)

```bash
sudo add-apt-repository ppa:git-core/ppa
```

* Redis (latest)

```bash
sudo add-apt-repository ppa:redislabs/redis
```

### Install required packages

```bash
sudo apt update
sudo apt install git nodejs redis-server telnet
```

### Redis server

#### Password (optional)

Generate a strong password:

```bash
makepasswd --chars=100
```

Edit Redis configuration file `/etc/redis/redis.conf`:

```bash
requirepass <redis_password>
```

_Note: documentation on securing Redis https://redis.io/topics/security_

#### Systemd

Enable and (re)start the Redis server service:

```bash
sudo systemctl enable redis-server
sudo systemctl restart redis-server
sudo systemctl status redis-server
```

## Website directory

Setup a directory for the data

```
sudo mkdir -pv /var/www/send
sudo chown www-data:www-data /var/www/send
sudo 750 /var/www/send
```

### NodeJS

Update npm:

```bash
sudo npm install -g npm
```

Checkout current NodeJS and npm versions:

```bash
node --version
npm --version
```

Clone repository, install JavaScript packages and compiles the assets:

```bash
sudo su -l www-data -s /bin/bash
cd /var/www/send
git clone https://gitlab.com/timvisee/send.git .
npm install
npm run build
exit
```

Create the file `/var/www/send/.env` used by Systemd with your environment variables
(checkout [config.js](../server/config.js) for more configuration environment variables):

```
BASE_URL='https://send.mydomain.com'
NODE_ENV='production'
PORT='8080'
REDIS_PASSWORD='<redis_password>'
S3_BUCKET='<s3_bucket_name>'
```

Lower files and folders permissions to user and group `www-data`:

```
sudo find /var/www/send -type d -exec chmod 750 {} \;
sudo find /var/www/send -type f -exec chmod 640 {} \;
sudo chmod 750 /var/www/send/node_modules/.bin/*
```

### Systemd

Create the file `/etc/systemd/system/send.service` with `root` user and `644` mode:

```
[Unit]
Description=Send
After=network.target
Requires=redis-server.service
Documentation=https://gitlab.com/timvisee/send
[Service]
Type=simple
ExecStart=/usr/bin/npm run prod
EnvironmentFile=/var/www/send/.env
WorkingDirectory=/var/www/send
User=www-data
Group=www-data
Restart=on-failure
[Install]
WantedBy=multi-user.target
```

_Note: could be better tuner to secure the service by restricting system permissions,
check with `systemd-analyze security send`_

Enable and start the Send service, check logs:

```
sudo systemctl daemon-reload
sudo systemctl enable send
sudo systemctl start send
sudo systemctl status send
journalctl -fu send
```
89 changes: 58 additions & 31 deletions docs/deployment.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
## Requirements

This document describes how to do a full deployment of Send on your own Linux server. You will need:

* A working (and ideally somewhat recent) installation of NodeJS and NPM
* GIT
* An Apache webserver
* A working (and ideally somewhat recent) installation of NodeJS and npm
* Git
* Apache webserver
* Optionally telnet, to be able to quickly check your installation

For Debian/Ubuntu systems this probably just means something like this:
For example in Debian/Ubuntu systems:

* apt install git apache2 nodejs npm telnet
```bash
sudo apt install git apache2 nodejs npm telnet
```

## Building

* We assume an already configured virtual-host on your webserver with an existing empty htdocs folder
* First, remove that htdocs folder - we will replace it with Send's version now
* git clone https://github.com/timvisee/send.git htdocs
Expand All @@ -19,51 +23,74 @@ For Debian/Ubuntu systems this probably just means something like this:
* npm run build

## Running

To have a permanently running version of Send as a background process:

* Create a file "run.sh" with:
```
* Create a file `run.sh` with:

```bash
#!/bin/bash
nohup su www-data -c "npm run prod" 2>/dev/null &
```
* chmod +x run.sh
* ./run.sh

* Execute the script:

```bash
chmod +x run.sh
./run.sh
```

Now the Send backend should be running on port 1443. You can check with:
* telnet localhost 1443

```bash
telnet localhost 1443
```

## Reverse Proxy

Of course, we don't want to expose the service on port 1443. Instead we want our normal webserver to forward all requests to Send ("Reverse proxy").

# Apache webserver

* a2enmod proxy
* a2enmod proxy_http
* a2enmod proxy_wstunnel
* a2enmod rewrite
* Enable Apache required modules:

```bash
sudo a2enmod headers
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel
sudo a2enmod rewrite
```

In your Apache virtual host configuration file, insert this:
* Edit your Apache virtual host configuration file, insert this:

```
# Enable rewrite engine
RewriteEngine on
# Enable rewrite engine
RewriteEngine on
# Make sure the original domain name is forwarded to Send
# Otherwise the generated URLs will be wrong
ProxyPreserveHost on
# Make sure the original domain name is forwarded to Send
# Otherwise the generated URLs will be wrong
ProxyPreserveHost on
# Make sure the generated URL is https://
RequestHeader set X-Forwarded-Proto https
# Make sure the generated URL is https://
RequestHeader set X-Forwarded-Proto https
# If it's a normal file (e.g. PNG, CSS) just return it
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule .* - [L]
# If it's a normal file (e.g. PNG, CSS) just return it
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule .* - [L]
# If it's a websocket connection, redirect it to a Send WS connection
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule /(.*) ws://127.0.0.1:1443/$1 [P,L]
# Otherwise redirect it to a normal HTTP connection
RewriteRule ^/(.*)$ http://127.0.0.1:1443/$1 [P,QSA]
ProxyPassReverse "/" "http://127.0.0.1:1443"
```

# If it's a websocket connection, redirect it to a Send WS connection
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule /(.*) ws://127.0.0.1:1443/$1 [P,L]
* Test configuration and restart Apache:

# Otherwise redirect it to a normal HTTP connection
RewriteRule ^/(.*)$ http://127.0.0.1:1443/$1 [P,QSA]
ProxyPassReverse "/" "http://127.0.0.1:1443"
```bash
sudo apache2ctl configtest
sudo systemctl restart apache2
```

0 comments on commit dc816d0

Please sign in to comment.