# Enabling SSL and HTTPS in our application

## What is SSL

Secure Socket Layer is a protocol that provides secure communication over two network devices. It ensures that the data transmitted between two devices remains private. The most common example would be the client computer (us) connecting to a secure server (for example a bank website).

The server usually has its own private key and public signed certificate. The private key is only known by the server and no one else. Here are the steps to establish SSL communication:

1. The publicly signed certificate is sent to the client for verification with the Certificate Authority (CA)
    
2. Once verified, the client sends a secret message encoded with the public certificate and sends it back to the server
    
3. The secret message can be decoded by the private key held by the server and read the contents of the message, thereby creating a new session whereby now only the client and server know this message.
    
4. Now both the client and server can use this message to encrypt and decrypt data with the session key
    

## Setting up SSL

We will be setting up SSL and HTTPS on our [Gitea application that we set up previously](https://blog.wongandre.com/running-internal-applications-on-proxmox). Previously our Gitea application only used HTTP for communication.

We will be exploring two ways to set up SSL/HTTPS:

1. Let Gitea handle SSL encryption/decryption by providing the private and public keys to our application
    
2. Let our reverse proxy (Nginx) handle SSL encryption/decryption instead and communicate using HTTP between the reverse proxy and Gitea
    

### Option 1

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1708767252447/67ef32b0-83e6-4c23-90fb-6099f9a05d7e.png align="center")

Most of the time applications have the option to enable SSL/HTTPS by specifying the private key and public self-signed certificate. Looking at the Gitea documentation to set up SSL, we need to change a few configurations in the `app.ini` file.

![from gitea HTTPS documentation](https://cdn.hashnode.com/res/hashnode/image/upload/v1708760764651/3ff90ff3-d8a6-46f7-b85d-3cf929805e28.png align="left")

1. Let's generate a private key for the CA
    
    ```bash
    # gitea GITEA_CUSTOM path
    cd /data/gitea/
    
    mkdir certs && cd ./certs
    
    # generate private key
    openssl genrsa -out giteaCA.key 2048
    ```
    
2. Create a self-signed certificate for the CA
    
    First, create a `csr` config to set our required information. The important parts here are the subjectAlternativeName. We will need to add the IP address to the Subject Alternative Name (SAN). This is important later when we want to use Gitea as our Kubernetes image repository.
    
    ```bash
    [req]
    default_bits = 2048
    prompt = no
    default_md = sha256
    distinguished_name = dn
    req_extensions = req_ext
    default_days = 900
    
    [dn]
    # The Common Name should be the fully qualified domain name (FQDN) of the server.
    # Replace "example.com" with your domain name.
    CN = 192.168.1.4
    
    [req_ext]
    # Subject Alternative Name (SAN) extension
    subjectAltName = @alt_names
    
    [alt_names]
    # Add additional subject alternative names (SANs) here.
    IP = 192.168.1.4
    ```
    
    After that we can use this csr to generate our certificate
    
3. ```bash
     openssl req -new -x509 -key giteaCA.key -out giteaCA.crt -config csr -extensions req_ext
    ```
    
    `` `-x509` `` : output should be an X.509 certificate instead of a certificate signing request
    
    `-days` : how long this certificate is valid for
    
    `-key` : the private key file used for generating the public certificate
    
    `-out` : specifies the name of the newly created public certificate
    
    `-config` : specifies the location of our configuration file
    
    `-externsions` : specifies that we are using extensions by passing in the var `req_ext` in our config file
    
4. Now we have giteaCA.key and giteaCA.crt
    
5. Looking at the Gitea `app.ini` file here. Our `ROOT_URL` here should be using HTTPS, `PROTOCOL` set to HTTPS and also we need to provide the path to our `CERT_FILE` and `KEY_FILE` as shown below
    
    ```plaintext
    [server]
    ...
    HTTP_PORT = 3000
    ROOT_URL = https://192.168.1.4:3000/
    PROTOCOL = https
    CERT_FILE = ./certs/giteaCA.crt
    KEY_FILE = ./certs/giteaCA.key
    ```
    
6. After editing the app.ini file we can restart our Gitea application
    
7. Verify that we can access the application via `https://192.168.1.4:3000` , however, it will give us a warning when we are accessing via a browser
    
    ![invalid certificate](https://cdn.hashnode.com/res/hashnode/image/upload/v1708751289337/5f875510-e07d-445f-8b28-f9b6513c0f27.png align="left")
    
    This is because the client PC that we are accessing our application failed to validate the public certificate that the server has sent us. To solve this issue, we need to add our `giteaCA.crt` file to the trusted root certificates. This can be done in different ways on different machines (windows, Mac, Linux, etc...) but won't be covered here for simplicity.
    

Option 1 is a simple way to set out SSL and HTTPS on the application itself.

### Option 2

We will add SSL and HTTPS to our Nginx reverse proxy instead and keep the Gitea application communication using HTTP. Here are a few reasons why we do this:

1. Sometimes enabling SSL on every application can be a hassle. If we have X number of applications needing to enable SSL, then we probably need to generate X private and public keys for each application. This can be reduced to 1 if we only use SSL up to the reverse proxy.
    
2. We might not want our application to handle SSL as it needs to use extra resources (ie CPU and memory) to handle SSL encryption and decryption.
    

As such, we sometimes let our network gateway, which is our reverse proxy also be the point where SSL is decrypted, and for the internal network communication is often done through http instead.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1708767262802/10132c26-e2f1-4d55-b9b6-42c60c5f9eb5.png align="center")

1. Let's create our certificate and key again, one-liner to generate it:
    
    ```bash
    openssl req -new -x509 -days 365 -newkey rsa:2048 -nodes -keyout ca.key -out ca.crt
    ```
    
2. Let's update our `nginx.conf` to include this certificate and key:
    
    ```nginx
    server {
        listen 443 ssl;
        server_name 192.168.1.4;
        ssl_certificate /certs/ca.crt;
        ssl_certificate_key /certs/ca.key;
    
        location /gitea/ {
    
            rewrite ^ $request_uri;
            rewrite ^/gitea(/.*) $1 break;
    
            proxy_pass http://192.168.1.4:3000$uri;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
    ```
    
    SSL uses port 443, which we will configure our server to listen to. `ssl_certifcate` and `ssl_certificate_key` we will provide a path from our side. We want our client to access Gitea using HTTPS using the domain: `https://192.168.1.4/gitea`, so we added a `/gitea/` location so that it can match our prefix with the URI.
    
    `rewrite ^/gitea(/.*) $1 break;` over here will then rewrite our URI from `gitea/($1)` to `($1)`, thereby removing the extra `gitea/` prefix before calling our proxy\_pass directive.
    
    For example, a client sending a request `https://192.168.1.4/gitea/user/login` will be modified to `http://192.168.1.4/user/login` in Nginx before forwarding this request. The URI being rewritten here is `/gitea/user/login` to `/user/login`.
    
3. If we are running our Nginx on a docker container, remember to enable port 443 under the ports section
    
    ```yaml
    version: "1.0"
    services:
      nginx:
        image: nginx:stable
        container_name: nginx
        volumes:
          - /home/internal/nginx/nginx.conf:/etc/nginx/conf.d/nginx.conf
          - /home/internal/nginx/access.log:/var/log/nginx/access.log
          - /home/internal/nginx/error.log:/var/log/nginx/error.log
          - /home/internal/certs/:/certs
        ports:
          - "80:80"
          # for SSL use only
          - "443:443"
    ```
    
4. Update the Gitea `app.ini` file to use the correct domain. This should be `192.168.1.4/gitea`
    
    ```plaintext
    [server]
    ...
    DOMAIN = 192.168.1.4/gitea
    SSH_DOMAIN = 192.168.1.4/gitea
    ROOT_URL = http://192.168.1.4:3000/gitea
    ```
    

Start our Nginx application and try to access our Gitea application through HTTPS again and it should work as well.
