Introduction: Restrict Access to Raspberry Pi Web Server

Picture of Restrict Access to Raspberry Pi Web Server

My Home Automation projects allow control via a web server over the internet. While internet access is very useful, it is a security risk. Reduce this risk by requiring HTTPS, creating a client-side certificate, and restricting access to only those devices that have the certificate installed.

SSL facilitates encryption and trust. Trust allows a browser to validate the authenticity of a web site. For this instructable, client-side SSL certificates can be used to authenticate a cell phone or laptop to a web server.

A server/client certificate pair prevents unauthorized users from accessing your home servers. For example, one of my web servers allows the garage door to be opened and closed from a cell phone. For a cell phone to open the garage door, it must have the client-side certificate installed.

Step 1: Gather Parts

For this instructable, I am using:

  • Raspberry Pi 2 Model B running Raspbian and Apache with working WiFi
  • U-verse 2-Wire Gateway
  • MacBook Pro


  • Text enclosed in spades, such as, ♣replace-this♣, should be replaced with an actual value. Of course, remove the spades.
  • References are included at the end

Step 2: ​Enable SSL and Generate Certificate (use HTTPS)

Open a terminal window on the MacBook and login into the Raspberry Pi using its IP address.

$ ssh pi@♣raspberry-pi-ip♣
login: ♣raspberry-pi-password♣

Generate a certificate key for the web server. You'll be asked to enter a pass phrase. This pass phrase can be anything, such as, ♣cert-password♣. Re-enter ♣cert-password♣.

$ sudo openssl genrsa -des3 -out server.key 1024
$ sudo openssl rsa -in server.key -out server.key.insecure 

The next command generates the certificate, and asks several questions (only the fully qualified domain name or FQDN matters):

$ sudo openssl req -new -key server.key -out server.csr 
$ sudo openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

Copy the certificate (cert) into the SSL directory

$ sudo cp server.crt /etc/ssl/certs 
$ sudo cp server.key /etc/ssl/private 

Enable SSL

$ sudo a2enmod ssl
$ sudo a2ensite default-ssl 

Restart apache (I am not sure which one to use. So, I did both)

$ sudo /etc/init.d/apache2 restart 
$ sudo service apache2 restart

Open a browser and in the url field enter: https://♣raspberry-pi-ip♣

A warning about the certificate not being from a trusted source will appear.

Press Continue. Make an exception and it should work.

Step 3: Creating Server/client Certificate Pair Using OpenSSL

Open a terminal window on the Mac and login to Raspberry Pi:

$ ssh pi@♣raspberry-pi-ip♣ 
login: ♣raspberry-pi-password♣ <br>

Remove keys made in previous step:

$ sudo rm server.key 
$ sudo rm server.crt 
$ sudo rm server.csr 
$ sudo rm server.key.insecure 

Generate Certificate Authority (CA)

Before creating server/client certificate, setup a self-signed Certificate Authority (CA), which can be used to sign the server/client certificates. Once created, the CA cert will act as the trusted authority for both your server and client certificates (or certs).

$ sudo openssl req -newkey rsa:4096 -keyform PEM -keyout ca.key -x509 -days 3650 -outform PEM -out ca.cer 

pass phrase = ♣cert-password♣ 

Generates: ca.cer, ca.key

Generate Apache server SSL key and certificate

Generate server.key:

$ sudo openssl genrsa -out server.key 4096 

Generate a certificate generation request.

$ sudo openssl req -new -key server.key -out server.req 

Use the certificate generation request and the CA cert to generate the server cert

$ sudo openssl x509 -req -in server.req -CA ca.cer -CAkey ca.key -set_serial 100 -extensions server -days 1460 -outform PEM -out server.cer 

Clean up – now that the cert has been created, we no longer need the request.

$ sudo rm server.req 

Install the server certificate in Apache

Copy the CA cert to a permanent place. We’ll need to specify our CA cert in Apache since it is a self generated CA and not one that is included in operating systems everywhere.

$ sudo cp ca.cer /etc/ssl/certs/ 

Copy the server cert and private key to permanent place.

$ sudo cp server.cer /etc/ssl/certs/server.crt 
$ sudo cp server.key /etc/ssl/private/server.key 

Activate the SSL module in Apache.

$ sudo a2enmod ssl  

Activate the SSL site in Apache

$ sudo a2ensite default-ssl

Disable the HTTP site

$ sudo a2dissite default 

Edit the config file for the SSL enabled site and add the lines below:

$ sudo nano /etc/apache2/sites-enabled/000-default-ssl SSLCACertificateFile /etc/ssl/certs/ca.cer SSLCertificateFile /etc/ssl/certs/server.crt SSLCertificateKeyFile /etc/ssl/private/server.key 

Apply the config in Apache.

$ sudo service apache2 restart 

Right now if you visit your https site, you will get an SSL error similar to “SSL peer was unable to negotiate an acceptable set of security parameters.” That is good – it means your site won’t accept a connection unless your browser is using a trusted client cert. We’ll generate one now.

Generate a client SSL certificate

Generate a private key for the SSL client.

$ sudo openssl genrsa -out client.key 4096 

Use the client’s private key to generate a cert request.

$ sudo openssl req -new -key client.key -out client.req 

Issue the client certificate using the cert request and the CA cert/key.

$ sudo openssl x509 -req -in client.req -CA ca.cer -CAkey ca.key -set_serial 101 -extensions client -days 365 -outform PEM -out client.cer 

Convert the client certificate and private key to pkcs#12 format for use by browsers.

$ sudo openssl pkcs12 -export -inkey client.key -in client.cer -out client.p12 

Clean up – remove the client private key, client cert and client request files as the pkcs12 has everything needed.

$ sudo rm client.key client.cer client.req

Step 4: Add Client-side Certificate to Devices

Import the client.p12 file into your browser.

To copy client.p12 from the Raspberry Pi to a Mac, open a terminal window and enter the command:

$ pwd
$ scp pi@♣raspberry-pi-ip♣:client.p12 /Users/♣your-username♣ 

Double click the file to import into the operating system’s keystore that will be used by IE and Chrome.

For Firefox, open the Options → Advanced → Certificates → View Certificates → Your Certificates and import the certificate.

For Android phones, the browser must be Chrome.

Email client.p12 as an attachment to your device.

Open the email on the Android phone and save the attachment to downloads

Go to home screen and open Settings → Security → Credential Storage → Install from device storage → Open the client.p12 file

Enter pass phrase: ♣cert-password♣

For Apple phones, email the cert and double click on it, then follow the directions.

Email client.p12 and ca.cer as attachments

Step 5: ​Disable HTTP in Apache

$ sudo nano /etc/apache2/ports.conf

Comment out these lines:

NameVirtualHost *:80
Listen 80

So it looks like:

# NameVirtualHost *:80
# Listen 80
Listen 443
NameVirtualHost *:443
<VirtualHost *:443>
	ServerName ♣raspberry-pi-hostname♣
	Redirect permanent https://♣u-verse-gateway-ip♣

Save the file (CTRL-o, ENTER, CTRL-x)

Restart Apache

$ sudo service apache2 restart

Step 6: Disable HTTP on U-verse Gateway

HTTPS is secure and uses port 443. HTTP is insecure and uses port 80. My internet service provider's (ISP) U-Verse 2-Wire gateway provides a firewall.

Login to U-verse 2-Wire Gateway.

On MacBook, open browser and enter: ♣u-verse-gateway-ip-address♣. My gateway's IP is

Go to: Settings → Firewall → Applications, Pinholes and DMZ

And, select ♣raspberry-pi-hostname♣

Remove applications that allow port 80 through the web server

Keep or add port 443 on HTTPS Server

Now, visit your website with the browser where you imported the client certificate. You’ll likely be prompted for which client certificate to use – select it. Then you’ll be authenticated and allowed in!

Check each device.

If they all work, then you are done!

Step 7: Appendix: References


Linwiz (author)2016-01-05

Have you heard of "Let's Encrypt"? It's free and you can use it to create a certificate in step 2 that will produce a valid certificate (not self signed, so no warning about the certificate not being from a trusted source will appear)

Thank you. I hadn't heard of Let's Encrypt.

About This Instructable




More by jeff.cartwright.562:The Absolutely Worst Raspberry Pi CaseMy Cord Cutting SystemBuild Kodi / OSMC Infrared Receiver and Reset Hat for Raspberry Pi
Add instructable to: