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:
The publicly signed certificate is sent to the client for verification with the Certificate Authority (CA)
Once verified, the client sends a secret message encoded with the public certificate and sends it back to the server
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.
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. Previously our Gitea application only used HTTP for communication.
We will be exploring two ways to set up SSL/HTTPS:
Let Gitea handle SSL encryption/decryption by providing the private and public keys to our application
Let our reverse proxy (Nginx) handle SSL encryption/decryption instead and communicate using HTTP between the reverse proxy and Gitea
Option 1
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.
Let's generate a private key for the CA
# gitea GITEA_CUSTOM path cd /data/gitea/ mkdir certs && cd ./certs # generate private key openssl genrsa -out giteaCA.key 2048
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.[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
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 varreq_ext
in our config fileNow we have giteaCA.key and giteaCA.crt
Looking at the Gitea
app.ini
file here. OurROOT_URL
here should be using HTTPS,PROTOCOL
set to HTTPS and also we need to provide the path to ourCERT_FILE
andKEY_FILE
as shown below[server] ... HTTP_PORT = 3000 ROOT_URL = https://192.168.1.4:3000/ PROTOCOL = https CERT_FILE = ./certs/giteaCA.crt KEY_FILE = ./certs/giteaCA.key
After editing the app.ini file we can restart our Gitea application
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 browserThis 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:
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.
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.
Let's create our certificate and key again, one-liner to generate it:
openssl req -new -x509 -days 365 -newkey rsa:2048 -nodes -keyout ca.key -out ca.crt
Let's update our
nginx.conf
to include this certificate and key: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
andssl_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 fromgitea/($1)
to($1)
, thereby removing the extragitea/
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 tohttp://192.168.1.4/user/login
in Nginx before forwarding this request. The URI being rewritten here is/gitea/user/login
to/user/login
.If we are running our Nginx on a docker container, remember to enable port 443 under the ports section
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"
Update the Gitea
app.ini
file to use the correct domain. This should be192.168.1.4/gitea
[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.