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:
let ip_addr = CONFIG.ip_address.as_ref.unwrap;
let socket_addr: SocketAddr = ip_addr.as_str.parse.unwrap;
serve
.run
.await;
- added tls code.
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;
serve
.tls
.cert_path
.key_path
.run
.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:- Spin up a temporary webserver (standalone)
- 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.
- ipaddress was changed from 127.0.0.1:3010 to 0.0.0.0:443.
- checked ufw status to ensure port 443 was allowed (using
$ sudo ufw status). - 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/hostsfile 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.
- ipaddress was changed from 127.0.0.1:3010 to 0.0.0.0:3010.
- added a rule in ufw to allow port 3010 (
$ sudo ufw allow 3010). - 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 file.
- Checked the browser with url: https://165.1.1.100:3010.
- Updated or ensured
/etc/hostsfile 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 <line-number-here>for deleting a row in nat table
$ sudo iptables -t filter -D FORWARD <line-number-here>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, 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 file. It was understood that a separate configuration file was required for each website.
Demo
Demo runs here.
License
MIT