# HTTPS Demo Demonstrates _how to build https website(s)_ in Rust. # Why this demo? It took good amount of time to complete my first https website; hence, documenting those learnings!. Hope, it may help others too!!. # Learnings Learned to use: - tls in code. - TLS certificate from Letsencrypt. - _nginx_ as reverse proxy on multiple https webservers. # Steps in making a secured website ## Step 1: Enabled tls support - Unsecured code looked like: ```rust let ip_addr = CONFIG.ip_address.as_ref().unwrap(); let socket_addr: SocketAddr = ip_addr.as_str().parse().unwrap(); warp::serve(routes) .run(socket_addr) .await; ``` - added tls code. ```rust let ip_addr = CONFIG.ip_address.as_ref().unwrap(); let cert_path = CONFIG.cert_path.as_ref().unwrap(); let key_path = CONFIG.key_path.as_ref().unwrap(); let socket_addr: SocketAddr = ip_addr.as_str().parse().unwrap(); warp::serve(routes) .tls() .cert_path(cert_path) .key_path(key_path) .run(socket_addr) .await; ``` - For local testing, used a sample certificate found in warp framework example. - Ran the server in development machine. - Tested it in the browser with url: _https​://localhost:3010_. - Ensured it was working. ## Step 2: On the Hosting machine, got a tls certificate - On the hosting machine (DigitalOcean in my case), a) ensured certbot was installed. b) ensured port 80 or 443 were available; those ports were not in use by other programs such as web servers, nginx, or apache. c) UFW (Uncomplicated Fire Wall) was disabled ( `$ sudo ufw disable` ). d) iptable entries, that were used for port forwarding to few __http__ websites, were deleted. - ran the following command successfully. `$ sudo certbot certonly --standalone -d example.com` - tried again for multiple domains. `$ sudo certbot certonly --standalone -d example.com -d www.example.com OR $ sudo certbot certonly --standalone -d example.com,www.example.com` - tried to add more domains after obtaining certificates. `$ sudo certbot certonly --expand -d example.com,www.example.com,new1.example.com,new2.example.com` It showed two options: 1. Spin up a temporary webserver (standalone) 2. Place files in webroot directory (webroot) Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 1 <-- selected option 1. - On success, it showed a `Congratulations!' message and place where certificates were stored. - Certificates were stored at `/etc/letsencrypt/live/example.com/`. - Checked the added certificates using following command. `$ sudo certbot certificates` - It showed certificate name, domains, certificate path, private key path. - For historical reasons, those certificate-containing-directories were created with permissions of __0700__ meaning that certificates were accessible only to servers that ran as the root user. - Fixed this using command: `$ sudo chmod 0755 /etc/letsencrypt/{live,archive}`. - It was also needed to use _chgrp_ and _chmod_ __0640__ to allow the server to read `/etc/letsencrypt/live/$domain/privkey.pem`. Please note, actual certificates and private keys were in archive folder; live folder contained only links to those files. Hence, applied _chmod_ and _chgrp_ command on __archive__ folder. ## Step 3: Deployed Website in several scenarios in an trial and error attempts ### Scenario 1: Deployed the website on port 443 - Made necessary configuration changes in __Settings.toml__ file. 1. ipaddress was changed from __127.0.0.1:3010__ to __0.0.0.0:443__. 2. checked ufw status to ensure port 443 was allowed (using `$ sudo ufw status`). 3. ensured Certificate Path and Key path were pointing to letsencrypt folder. - Ran the website on command line ( _$ ./example_ ). - Checked in the browser with url like: _https​://165.1.1.100_ ; where 165.1.1.100 was the IP address of the hosting machine. - Updated `/etc/hosts` file with an entry of __127.0.0.1 example.com__. - Checked the browser with url: _https​://example.com_. ### Scenario 2: Deployed the website on port 3010 - Made necessary configuration changes in __Settings.toml__ file. 1. ipaddress was changed from 127.0.0.1:3010 to 0.0.0.0:3010. 2. added a rule in ufw to allow port 3010 ( `$ sudo ufw allow 3010` ). 3. ensured Certificate Path and Key path was pointing to letsencrypt folder. - Ran the website on command line ( _$ ./example_ ). - To run it as a service, referred instructions in [https_demo.service](https://github.com/mohankumaranna/https_demo/blob/master/https_demo.service) file. - Checked the browser with url: _https​://165.1.1.100:3010_. - Updated or ensured `/etc/hosts` file with an entry of __127.0.0.1 example.com__. - Checked the browser with url: _https​://example.com:3010_. - To avoid port number in the url, port forwarding rules were added into iptables; commands were: a) `$ sudo sysctl net.ipv4.conf.ens3.forwarding=1` note: network interface ens3 was identified through `$ sudo ifconfig`. b) `$ sudo iptables -A PREROUTING -t nat -i ens3 -p tcp --dport 443 -j REDIRECT --to-ports 3010` c) `$ sudo iptables -A FORWARD -t filter -p tcp -d 165.1.1.10 --dport 3010 -j ACCEPT` d) Checked whether updates were done using: `$ sudo iptables -t nat -L PREROUTING -n -v --line-numbers` `$ sudo iptables -t filter -L FORWARD -n -v --line-numbers` e) in case of errors, noted down the row number from above commands and used it in: `$ sudo iptables -t nat -D PREROUTING ` for deleting a row in nat table `$ sudo iptables -t filter -D FORWARD ` for deleting a row in filter table _Note: -A is for Add, -t for table, -p for protocol, -i for interface, -L for Listing, -D for Delete_. - Checked the browser with url: _https​://example.com_ (note: no port number this time). ### Scenario 3: Deployed multiple websites - Above two scenarios worked for single website. - To run multiple websites on the same machine, a reverse-proxy server (also known as Gateways) was required. - Though a Rust tool on [reverse-proxy](https://github.com/mohankumaranna/traffic_router_async), for http, was coded based on __Hyper__ example __Gateways__, it could not be used for https. So, __nginx__ server was used for reverse-proxying. - installed _nginx_ server on the hosting machine. - tested it was working. - referred _nginx_ configuration steps in [https-demo.eastgate.in](https://github.com/mohankumaranna/https_demo/blob/master/https-demo.eastgate.in) file. It was understood that a separate configuration file was required for each website. # Demo Demo runs [here](https://https-demo.eastgate.in/). # License MIT