Secure Your Site Using HTTPS with Self-Signed or CA SSL Certificates on Ubuntu 22.04

No one wants to have their sensitive data hijacked because of bad web security practices, and securing your web traffic with SSL/TLS encryption to handle HTTPS communications has become an essential part of building any public or private web service, because without it, your web service will have weak privacy and insecure data transfer, and users won’t trust your services.

SSL/TLS encryption protects your data transfer and prevents sensitive data exposure, in addition to ensuring that the connection is between the correct entities by cryptographically verifying that you’re connecting with an authentic server, and that the messages have not been interfered with while being transferred.

The SSL/TLS certificate's job is to initiate secure sessions with the user’s browser via the Transport Layer Security (TLS), which is based on the now-deprecated secure sockets layer (SSL) protocol. This secure connection cannot be established without the SSL/TLS certificate which digitally authenticates a website's identity and tells web users that a connection is safe and secure.

Note: From now on we will refer to SSL/TLS certificates as simply "SSL certificates" for brevity.

In this article, we will show you how to secure your website and protect your customers’ online transactions, by making sure that their sensitive information, such as their credit card number or personal information, are only being transmitted to and from legitimate online businesses like yours, and that they are encrypted.

We will briefly outline the main differences between self-signed and Certificate Authority (CA) certificates. You will configure your Apache or NGINX web server to use a self-signed certificate to encrypt your testing environment and internal data transfer. And you will also learn how to secure both Apache and the NGINX web servers by obtaining and installing a free SSL certificate issued by Let’s Encrypt— a Certificate Authority (CA), which will allow you to communicate and transmit data via encrypted HTTPS connections on your web servers for production.

Distinction Between Self-Signed and CA Certificates

In this section, we will briefly outline the main differences between 2 types of certificates you can implement: self-signed and CA certificates. For a comprehensive analysis of both types of certificates, you can check our dedicated blog article: “What are SSL Server Certificates and how do they protect my website?”.

  • Self-signed certificates are convenient when used in private networks and testing environments.
  • CA certificates are suitable for all production public-facing websites and software.
  • CA certificates signed by a publicly trusted CA can build trust among website visitors, and establish reputation.

Ready to get your hands dirty? Let’s GO!

Creating and Installing a Self-Signed SSL Certificate

Step 1) Creating the Self-Signed Certificate

In this step, you will use OpenSSL to create a certificate that will store some basic information about your site, accompanied by an SSL private key file that will be kept secret in the server, and the server then will use it to securely handle encrypted data. OpenSSL is a software library that provides tools for general-purpose cryptography and secure communications. It is used by most HTTPS-based websites, because it provides an open-source implementation of the SSL and TLS protocols.

The private SSL key is used by the server to encrypt the content it sends to clients (e.g., web browser) The public SSL certificate is shared publicly with clients requesting the content. So when you request a page, the browser gets the SSL certificate from the server, and uses it to decrypt and access the content signed by the associated private SSL key.

The first step to obtaining an SSL certificate is using OpenSSL to create a certificate signing request (CSR). In normal cases, the CSR will be sent to the Certificate Authority (CA) which in turn will create a certificate based on it. In our case (self-signed certificate), we will create the certificate ourselves based on this CSR we generate using OpenSSL. The CSR contains the common name(s) you want your certificate to secure, information about your company, and your public key. In order for a CSR to be created, it needs to have a private key from which the public key is extracted. This can be done by using an existing private key or generating a new private key.

Note: It is strongly recommended to generate a new private key when creating a CSR instead of using an existing one.

To create a certificate signing request (CSR) and a private key with the openssl library, you will use the openssl req command with the following command structure:

openssl req -x509 -newkey rsa:<rsa_value> -nodes -out <public certificate path> -keyout <private key path> -days <certificate duration in days> -subj "C=<country code>/O=<organization name>/OU=<organizational unit>/CN=<common name>"

Here is what each part of the preceding command means:

  • -x509: A multi-purpose certificate utility. It can be used to display certificate information, convert certificates to various forms, sign certificate requests like a "mini CA" or edit certificate trust settings.
  • -newkey: Specifies that a new private key should be created with the certificate request.
  • -rsa:: The encryption algorithm you’ll use to generate your key. While you can use other encryption algorithms if you want, RSA is one of the best encryption systems that you can use to protect your data in transmission, especially because it comes with great compatibility. `` represents the key size in bits.
  • -nodes: is not the English word "nodes", it refers, instead, to "no DES". When given as an argument, it means OpenSSL will not encrypt the private key in a PKCS#12 file, and the private key will not have a passphrase. This is important for the web server to have access to the certificate file without needing a passphrase. Otherwise the server would wait for the user to manually enter the passphrase every time the server restarts, which is not convenient.
  • -out: defines the path the public key will be generated to, including the filename.
  • -keyout: defines the path the private key will be generated to, including the filename.
  • -days: The certificate’s lifetime in days.
  • -subj: is used to provide all the necessary information within the command itself, instead of having to provide each required piece of information via command line prompts.
    • C defines the two-letter country code where your company is legally located.
    • O defines the organization’s name.
    • OU defines the organizational unit name, which can be the name of your department within the organization.
    • CN is the common name, where you either enter the fully-qualified domain name (FQDN) you’ll use to access the server by (e.g., www.example.com), or the public IP of the server.

Now that you are familiar with the openssl command options and actions, you can form and execute an openssl command to generate a certificate signing request (CSR) as follows:

sudo openssl req -x509 -newkey rsa:4096 -nodes -out /etc/ssl/certs/ssl-selfsigned.pem -keyout /etc/ssl/private/ssl-selfsigned.key -days 365 -subj "/C=US/O=MyCompany/OU=Technical Department/CN=www.example.com"

This will generate two files automatically created under the respective subdirectories you’ve declared:

  • /etc/ssl/private/: will be the location of the SSL private key file.
  • /etc/ssl/certs/: will be the location of your CSR file.

In our example, this means that the two following files will be generated:

  • /etc/ssl/private/ssl-selfsigned.key: your SSL private key file.
  • /etc/ssl/certs/ssl-selfsigned.pem: your CSR file, which you can use as a self-signed certificate.

Step 2) Configuring Your Web Server to Use a Self-Signed Certificate.

Now that you have your very own self-signed SSL certificate in the form of a CSR file, you can use it to encrypt your data and serve HTTPS requests. To do so, you need to configure your web server to use it. In this step, you’ll learn how to configure and use your self-signed SSL certificate on the two most popular HTTP web servers: Apache, and NGINX.

Configuring the Apache Web Server to Use a Self-Signed SSL Certificate

Apache Logo

In this section, you’ll learn how to configure the Apache web server to use your self-signed SSL certificate.

First, open Apache’s default configuration file:

sudo nano /etc/apache2/sites-enabled/000-default.conf

By default, your Apache welcome page loads on port 80 without an SSL certificate.

Your Apache’s default configuration will be similar to the following:

<VirtualHost *:80>
        Define servername www.example.com
        ServerName ${SERVERNAME}
        ServerAdmin [email protected]
        DocumentRoot /var/www/html
</VirtualHost>

Replace the existing content with the following configuration, and make sure to set the correct values where needed (highlighted in yellow below):

<VirtualHost *:80>
        Define servername www.example.com
        ServerName ${SERVERNAME}
        RewriteEngine on
        RewriteRule ^/.*$ https://\${SERVERNAME}%{SCRIPT_FILENAME}?%{QUERY_STRING} [R=301]
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
<VirtualHost *:443>
        SSLEngine On
        SSLCertificateFile /etc/ssl/certs/ssl-selfsigned.pem
        SSLCertificateKeyFile /etc/ssl/private/ssl-selfsigned.key
        ServerName ${SERVERNAME}
        DocumentRoot /var/www/html
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Here you add two configurations, one for HTTP connections on port 80, and one for HTTPS on port 443.

In the HTTP configuration, you use the RewriteEngine and RewriteRule to redirect HTTP requests to HTTPS. And you also set locations for log files.
In the HTTPS configuration, you set the SSLEngine directive to On to enable the SSL/TLS Protocol Engine. You set the paths of the self-signed SSL certificate and the SSL private key files you generated earlier. You declare the server name, and the document root directory that holds the files Apache serves. And you also set locations for log files.

Next, use the a2enmod tool to enable the SSL and the RewriteEngine Apache modules. This allows Apache to use SSL/TLS encryption, and the RewriteEngine feature to rewrite requested URLs and redirect users from HTTP to HTTPS:

sudo a2enmod ssl rewrite

Next, test for configuration errors:

sudo apache2ctl configtest

You should receive an output that contains the text Syntax OK, which means you can safely reload Apache, otherwise, you will get a very specific description pointing out the error you have to fix.

Next, restart Apache:

sudo systemctl restart apache2

Now visit your website’s domain name or IP address using https:// at the beginning:

https://domain_name_or_IP

You should see an error telling you that the website is not secure. This means that the self-signed certificate is properly installed, but because the browser does not recognize your certificate as valid, you’ll receive this error. As we’ve mentioned earlier, this self-signed certificate is only for testing purposes and internal use, and not to secure your website for production, because your certificate is not signed by any of the browser’s known certificate authorities. But don’t worry, we will fix this later in this article using a certificate that browsers trust.

Now that you’ve learned how to configure Apache to use a self-signed certificate, you’ll see how to do the same with an NGINX server.

Configuring the NGINX Web Server to Use a Self-Signed SSL Certificate

NGINX logo

In this section, you’ll learn how to configure the NGINX web server to use your self-signed SSL certificate.

First, open NGINX’s default configuration file:

sudo nano /etc/nginx/sites-enabled/default

By default, your NGINX welcome page loads on port 80 without an SSL certificate. So, you would see something similar to the following configuration:

server {
        listen 80;
        listen [::]:80;
        root /var/www/html;

        index index.html index.htm index.nginx-debian.html;

        server_name www.example.com;
        location / {
                    try_files $uri $uri/ =404;
        }
}

Replace the existing content with the following configuration, and make sure to set the correct values where needed (highlighted in yellow below):

server {
    listen 80;
    listen [::]:80;
    server_name www.example.com;
    access_log off;
    location / {
        rewrite ^ https://$host$request_uri? permanent;
    }
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name www.example.com;
    root /var/www/html;
    index index.php index.html index.htm index.nginx-debian.html;
    autoindex off;
    ssl_certificate /etc/ssl/certs/ssl-selfsigned.pem;
    ssl_certificate_key /etc/ssl/private/ssl-selfsigned.key;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers HIGH:!aNULL:!MD5;

    location ~ \.php$ {
         include snippets/fastcgi-php.conf;
         fastcgi_pass unix:/var/run/php/php-fpm.sock;
         fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
         include fastcgi_params;
    }
}

Here, you have two server blocks representing configuration for two ports: port 80 which serves HTTP requests, and port 443 that serves HTTPS requests.

Notice that, in the HTTP configuration, you use the rewrite directive in the location block to redirect HTTP requests to HTTPS.

In the HTTPS configuration, you set up NGINX to use SSL and set the path of the self-signed SSL certificate file and the SSL private key file you generated earlier. In the location ~ \.php$, you set up NGINX to process PHP files with the php-fpm package.

With the configuration file modified, check for syntax errors in it using the following command:

sudo nginx -t

The output should let you know that the configuration file test is successful.
Now, restart NGINX:

sudo systemctl restart nginx

Now visit your website’s domain name or IP address using https:// at the beginning:

https://domain_name_or_IP

Again, you should see an error telling you that the website is not secure, as this self-signed certificate is only for testing purposes and internal use, and not to secure your website for production, because your certificate is not signed by any of the browser’s known certificate authorities. Again, don’t worry, we will fix this later in this article.

Apache &amp; NGINX logos

The Common Parts Between Apache and NGINX

This section will outline the commonalities between using a self-signed SSL certificate with the Apache web server and the NGINX web server.

Notes:

  • In the configuration files of both Apache and NGINX, remember to set the server name value to whatever you intend to address your server with. This can be a hostname, full domain name, or an IP address, and make sure it matches the Common Name you chose when creating the certificate. In Apache, the server name is configured using the ServerName directive, and in NGINX, it’s the server_name directive.
  • The document root is the root directory you serve your web files from. It is configured using the DocumentRoot directive in Apache, and the root directive in NGINX.
  • The redirection configurations we’ve added introduce the good practice of responding on port 80, even if you want to force all traffic to be encrypted. Whenever a user requests a page using an HTTP request, they will be automatically redirected to the HTTPS equivalent of the URL they’ve requested. You can test this new redirect functionality by visiting your site with plain http://and you’ll notice that you will be automatically redirected to a URL beginning with https://.
  • If you visit your site in a browser, prefixing https:// to the URL, you would get an error, explaining that your website is not secure as mentioned above.This means that the browser can’t verify the identity of the server, since the certificate is not signed by any of its known certificate authorities.

On receiving the browser error that tells you that the connection is not secure, click the Advanced button or More information depending on the browser, and choose to proceed. The following is an example of the error in the Google Chrome browser:

Once you proceed, your browser will load the Apache or NGINX welcome page, but with a noticeable danger icon and a Not Secure label at the beginning of your URL.

If you click the danger icon, the browser will inform you that the certificate is not valid:

Apache web server (Welcome page)

Nginx web server (Welcome page)

In the pop-ups above, click on “Certificate is not valid” for more details on the self-signed certificate. (Note the 1-year duration, we’ve declared using the days value on the certificate’s creation).

Creating and Installing a CA Certificate

To secure your website using an SSL certificate that browsers trust, you’ll need to install a certificate that’s issued by a Certificate Authority (CA). In this section, we’ll walk through how to install a certificate from Let's Encrypt, which is a renowned Certificate Authority (launched by the EFF, Mozilla, and others) that allows you to obtain an SSL CA certificate free of charge.

Before we install a Let's Encrypt certificate, we’ll outline the difference between it and other CA authorities.

The Difference Between Let's Encrypt & Other CA-Issued Certificates

  • Let's Encrypt certificates are Free!
  • They are only valid for 90 days, whereas other SSL certificates are valid for at least one year, with the option of longer validity periods. But because Let's Encrypt certificates can be automatically and freely renewed, there isn’t much of a difference in terms of validity periods.
  • Let's Encrypt only offers domain-validated certificates (DV). You might go for other CA providers if you need the extra security of an extended validation certificate (EV) for your site.
  • Let's Encrypt does not offer wildcard or multi-domain certificates, while many other CA providers do.

How to Procure and Install non-Let's-Encrypt CA Certificates

1) Create a Certificate Signing Request (CSR)

Generated on the same server you plan to install the certificate on, the CSR contains information (e.g. common name, organization, country) which the Certificate Authority (CA) will use to create your certificate. It also contains the public key that will be included in your certificate and is signed with the corresponding private key.
Please refer to the above section describing CSR creation for self-signed certificates (which also applies to CA certificates).

2) Upload the CSR to the Certificate Authority (CA)

Please refer to the documentation of the certificate authority of your choice, and follow their instructions to properly upload your certificate signing request, along with any additional information.

Once the CSR is uploaded, the CA replies with your final certificate ready to use.
See the sections below to learn how to install your certificate depending on your web server's type.

How to Procure and Install Let's Encrypt Certificates

Step 1) Creating The Let's Encrypt Certificate

In this step, we will cover how to get an SSL certificate from Let's Encrypt using the certbot command line tool, which automates the process of getting and installing a Let's Encrypt certificate valid for 90 days, with the possibility of an automated renewal.

Note: TCP ports 80 (HTTP) & 443 (HTTPS) must be opened on the server firewall for these instructions to work.
First, you will need to install the certbot command line tool, to use it as a client that interacts with Let's Encrypt to create the SSL certificate, which you can then use with Apache, NGINX, or any other web server. Use the apt command to install certbot:

sudo apt install -y certbot

To create a Let’s Encrypt certificate with certbot, you’ll use the following command structure:

sudo certbot certonly --webroot --webroot-path WEB_SERVER_ROOT_PATH -m EMAIL -d DOMAIN --agree-tos -n

Here is what each part of the preceding command means:

  • certonly: (certificate only) used to just obtain the certificate without installing it anywhere.
  • --webroot: An option that is used here to keep the web server running while Certbot runs, since we’re already running a local web server, and don't want to stop it during the certificate issuance process.
  • --webroot-path or -w: Defines the top-level directory (“web root”) containing the files served by your webserver. Note that the web root path must be the path on which files from the domain are served. In our example, it's the web root path from which our http://www.example.com URL serves files.
  • --mail or -m : The email which will be used by the certificate authority to alert you when a domain will expire.
  • --domain or -d: The domain name you’ll use to access the server by.--agree-tos: Confirms our agreement to the ACME server's subscriber agreement.
  • --non-interactive or -n is used to execute the command without ever asking for user input or prompts.
    Now that you are familiar with the certbot options and actions, you can form and execute a certbot command to create a certificate. For example, you can use the following command, making sure to set the appropriate values for your case:
sudo certbot certonly --webroot --webroot-path /var/www/html/ -m [email protected] -d www.example.com --agree-tos -n`

Once the command is executed, the following two files will be automatically created under the respective subdirectories as follows:

  • The private key: /etc/letsencrypt/live/www.example.com/privkey.pem
  • The certificate: /etc/letsencrypt/live/www.example.com/fullchain.pem

Now that you have your Let's Encrypt private key file and your certificate file, you can install your certificate on your web server.

Step 2) Installing Your Let's Encrypt Certificate on Your Web Server

Apache Logo

Now that you’ve created a Let’s Encrypt certificate, you can configure your web server to use it and secure your website traffic with HTTPS encryption. In this step, you’ll learn how to configure both Apache and NGINX to use the Let’s Encrypt certificate you’ve created.

Configuring the Apache Web Server to Use the Let’s Encrypt Certificate

Now that you’ve created a Let’s Encrypt certificate, you can configure your Apache server to use it and enable HTTPS on your website.
First, edit apache’s default configuration file:

sudo nano /etc/apache2/sites-enabled/000-default.conf

Replace the key and the certificate paths with the Let’s Encrypt private key file and the certificate file (the changes you have to make are highlighted in yellow in the code below):

<VirtualHost *:80>
        Define servername www.example.com
        ServerName ${SERVERNAME}
        RewriteEngine on
        RewriteRule ^/.*$ https://\${SERVERNAME}%{SCRIPT_FILENAME}?%{QUERY_STRING} [R=301]
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
<VirtualHost *:443>
        SSLEngine On
        SSLCertificateFile /etc/letsencrypt/live/www.example.com/fullchain.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/www.example.com/privkey.pem
        ServerName ${SERVERNAME}
        DocumentRoot /var/www/html
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Here, you set the SSLCertificateFile directive to the path of the Let’s Encrypt certificate file, and you set the SSLCertificateKeyFile directive to the private key’s path.
Next, test for configuration errors:

sudo apache2ctl configtest

You should receive an output that contains the text Syntax OK, which means you can safely reload Apache, otherwise, you will get a very specific description pointing out the error you have to fix.
Next, restart Apache:

sudo systemctl restart apache2

Now, reload your website in the browser. You will notice a secured padlock with a valid certificate message as you can see in the following example, which was taken from the Google Chrome browser:

With this, you now have HTTPS enabled in your Apache web server, and you can now secure your web traffic, which establishes customer trust and protects both your internal and customer data.

Configuring the NGINX Web Server to Use the Let’s Encrypt Certificate

To configure your Let’s Encrypt certificate with your NGINX server and enable HTTPS on your website. First, edit NGINX’s default configuration file:

sudo nano /etc/nginx/sites-enabled/default

Replace the private key and the certificate paths with the Let’s Encrypt private key file and the certificate file (the changes you have to make are highlighted in yellow in the code below):

server {
   listen 80;
   listen [::]:80;
   server_name www.example.com;
   access_log off;
   location / {
         rewrite ^ https://$host$request_uri? permanent;
   }
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name www.example.com;
    root /var/www/html;
    index index.php index.html index.htm index.nginx-debian.html;
    autoindex off;
    ssl_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers HIGH:!aNULL:!MD5;

    location ~ \.php$ {
         include snippets/fastcgi-php.conf;
         fastcgi_pass unix:/var/run/php/php-fpm.sock;
         fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
         include fastcgi_params;
    }
}

Here, you set the ssl_certificate directive to the Let’s Encrypt certificate file path you created earlier, and the ssl_certificate_key directive to the Let’s Encrypt private key file path.
With the configuration file modified, check for syntax errors in it using the following command:

sudo nginx -t

The output should let you know that the configuration file test is successful.
Now, restart NGINX:

sudo systemctl restart nginx

Reload your browser and you will notice a secured padlock with a valid certificate message as follows:

With this, you now have HTTPS enabled in your NGINX web server, and you can now secure your web traffic, which establishes customer trust and protects both your internal and customer data.

Checking Your Certificate Information

In the pop-up that comes up when clicking the padlock on the left side of the URL, click on “Certificate is secure” for more details on the CA certificate:

Congrats!

Your website has become CA certified and you can now securely transfer data through HTTPS, and protect your online transactions, and with best security practices, you can handle paid subscriptions, eCommerce orders, memberships, or charity and online fundraising.

Reader Alert

If you feel that creating a self-signed SSL certificate is too technical, time-consuming, or beyond your expertise, you can choose a very convenient and practical solution, ready-made, fully tested, and developed by SSD Nodes (That is us 😊). Just visit our website, choose the server’s specifications that fit your needs, along with any of the 1-Click Applications we offer (WordPress, Zabbix, phpMyAdmin, Webmin, Nextcloud, LAMP, LEMP, Grafana, MongoDB to name a few), complete your checkout, and in a couple of minutes, our smart algorithms will make your application ready to use with an active SSL self-signed certificate! Way practical, isn’t it?

If you want to try out the instructions for securing your web server with Let's Encrypt and use HTTPS on a server publicly, check out our incredibly cheap, simple, and high-value VPS plans.

If you liked this article, share it with your friends & colleagues on Facebook, Twitter, Reddit, etc. You can use the "share" buttons on your right.

Find more blog articles, tutorials, comparisons, opinions & how-tos on Serverwise. If you want us to write on a particular topic, please drop a line to our Editorial team at [email protected]

Looking for reliable cloud hosting with minimal down time ready to be deployed across 12 global locations in minutes? Our plans start at $50 per year only (open specs). Looking to scale up your hosting? Save thousands on premium plans. Check out our latest deals & freebies here.