Gitea and Jenkins with Nginx SSL Proxy on Ubuntu

Install Ubuntu 20.04

I install a minimal desktop instance.

Install packages needed for later:

apt-get install -y vim git build-essential openssh-server curl wget

Update and upgrade:

sudo -i
apt-get update
apt-get upgrade

Open the firewall ports needed for later:

ufw allow 8080
ufw allow 22
ufw allow 3000
ufw allow 80
ufw allow 443
ufw allow 8443

ufw enable
ufw status

Install Gitea

First install MariaDB Server for use with Gitea:

apt-get install -y mariadb-server
mysql_secure_installation

Set a password

Select yes to the remaining questions.

Create a database to make sure everything is working correctly, change the password to your own:

mysql -u root -p   
create database gitea;
grant all privileges on gitea.* to 'gitea'@localhost identified by 'password';
quit;

Add the Gitea repository, install Gitea and start it:

curl -sL -o /etc/apt/trusted.gpg.d/morph027-gitea.asc https://packaging.gitlab.io/gitea/gpg.key

echo "deb [arch=amd64] https://packaging.gitlab.io/gitea gitea main" | sudo tee /etc/apt/sources.list.d/morph027-gitea.list

apt-get update
apt-get install -y gitea

systemctl start gitea
systemctl enable gitea

Create the log directory:

mkdir -p /var/log/gitea

Go to the Gitea web page on your server:

http://ip.add.re.ss:3000 

Also make sure you can get there by name:

http://gitea.home.local:3000

Create the Administrator Username and password. Make changes to the Gitea configuration as you feel appropriate, however, the log path should now be:

/var/log/gitea

Change the log directory ownership:

chown gitea:gitea /var/log/gitea
<p id="On Gitea create an organization:
Dashboard -> Organization
Organization Name: Home

Add the jenkins user:
Site Administration -> User Accounts -> Create User Account
Do not require the user to change the password on next login.

People:
    jenkins
    jud

Install Jenkins

First install the Jenkins prerequisites:

apt-get install openjdk-11-jdk
java -version
openjdk version "11.0.11" 2021-04-20
OpenJDK Runtime Environment (build 11.0.11+9-Ubuntu-0ubuntu2.20.04)
OpenJDK 64-Bit Server VM (build 11.0.11+9-Ubuntu-0ubuntu2.20.04, mixed mode, sharing)

Add the Jenkins repository and install Jenkins:

wget -q -O - https://pkg.jenkins.io/debian-stable/jenkins.io.key | sudo apt-key add -

sh -c 'echo deb http://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list'

apt-get update
apt-get install -y jenkins

Unlock Jenkins by go to the URL:
http://192.168.128.65:8080

cat /var/lib/jenkins/secrets/initialAdminPassword 
9c48273795be49b39aa2ba4a99ce5f93

Paste the code into the Administrator password field.

Install the suggested plugins.

Create the first Admin User.

Create the Self-signed Certificate

Back up the SSL configuration file and create a Jenkins configuration file.

cp /etc/ssl/openssl.cnf /etc/ssl/openssl.cnf.0
cp /etc/ssl/openssl.cnf /etc/ssl/jenkins.cnf

Edit the jenkins file and add the subject_alt_name stanza below in the [ v3_va ] section:

vim /etc/ssl/jenkins.cnf
[ v3_ca ]
subjectAltName = @alt_names

[ alt_names ]
DNS.1 = gitea
DNS.2 = gitea.home.local
DNS.3 = jenkins
DNS.4 = jenkins.home.local
DNS.5 = localhost
IP.1 = 127.0.0.1
IP.2 = 192.168.128.65

This is the jenkins.cnf file I used. Copy this file into the /etc/ssl directory.

cat /etc/ssl/jenkins.cnf | egrep -v ^#
HOME			= .
oid_section		= new_oids
[ new_oids ]
tsa_policy1 = 1.2.3.4.1
tsa_policy2 = 1.2.3.4.5.6
tsa_policy3 = 1.2.3.4.5.7

[ ca ]
default_ca	= CA_default		# The default ca section

[ CA_default ]
dir		= ./demoCA		# Where everything is kept
certs		= $dir/certs		# Where the issued certs are kept
crl_dir		= $dir/crl		# Where the issued crl are kept
database	= $dir/index.txt	# database index file.
					# several certs with same subject.
new_certs_dir	= $dir/newcerts		# default place for new certs.

certificate	= $dir/cacert.pem 	# The CA certificate
serial		= $dir/serial 		# The current serial number
crlnumber	= $dir/crlnumber	# the current crl number
					# must be commented out to leave a V1 CRL
crl		= $dir/crl.pem 		# The current CRL
private_key	= $dir/private/cakey.pem# The private key

x509_extensions	= usr_cert		# The extensions to add to the cert

name_opt 	= ca_default		# Subject Name options
cert_opt 	= ca_default		# Certificate field options

default_days	= 365			# how long to certify for
default_crl_days= 30			# how long before next CRL
default_md	= default		# use public key default MD
preserve	= no			# keep passed DN ordering

policy		= policy_match

[ policy_match ]
countryName		= match
stateOrProvinceName	= match
organizationName	= match
organizationalUnitName	= optional
commonName		= supplied
emailAddress		= optional

[ policy_anything ]
countryName		= optional
stateOrProvinceName	= optional
localityName		= optional
organizationName	= optional
organizationalUnitName	= optional
commonName		= supplied
emailAddress		= optional

[ req ]
default_bits		= 2048
default_keyfile 	= privkey.pem
distinguished_name	= req_distinguished_name
attributes		= req_attributes
x509_extensions	= v3_ca	# The extensions to add to the self signed cert
string_mask = utf8only

req_extensions = v3_req # The extensions to add to a certificate request

[ req_ext ]
subjectKeyIdentifier        = hash
basicConstraints        = CA:FALSE
keyUsage            = digitalSignature, keyEncipherment
nsComment           = "OpenSSL Generated Certificate"


[ req_distinguished_name ]
countryName			= Country Name (2 letter code)
countryName_default		= US
countryName_min			= 2
countryName_max			= 2
stateOrProvinceName		= State or Province Name (full name)
stateOrProvinceName_default	= Georgia
localityName			= Locality Name (eg, city)
localityName_default		= Evans
0.organizationName		= Organization Name (eg, company)
0.organizationName_default	= Home
organizationalUnitName		= Organizational Unit Name (eg, section)
organizationalUnitName_default	= Office
commonName			= Common Name (e.g. server FQDN or YOUR name)
commonName_max			= 64
emailAddress			= Email Address
emailAddress_max		= 64

[ req_attributes ]
challengePassword		= A challenge password
challengePassword_min		= 4
challengePassword_max		= 20
unstructuredName		= An optional company name

[ usr_cert ]
basicConstraints=CA:FALSE
nsComment			= "OpenSSL Generated Certificate"
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer

[ v3_req ]
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment

[ v3_ca ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
basicConstraints = critical,CA:true
subjectAltName = @alt_names

[ crl_ext ]
authorityKeyIdentifier=keyid:always

[ proxy_cert_ext ]
basicConstraints=CA:FALSE
nsComment			= "OpenSSL Generated Certificate"
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo

[ tsa ]
default_tsa = tsa_config1	# the default TSA section

[ tsa_config1 ]
dir		= ./demoCA		# TSA root directory
serial		= $dir/tsaserial	# The current serial number (mandatory)
crypto_device	= builtin		# OpenSSL engine to use for signing
signer_cert	= $dir/tsacert.pem 	# The TSA signing certificate
					# (optional)
certs		= $dir/cacert.pem	# Certificate chain to include in reply
					# (optional)
signer_key	= $dir/private/tsakey.pem # The TSA private key (optional)
signer_digest  = sha256			# Signing digest to use. (Optional)
default_policy	= tsa_policy1		# Policy if request did not specify it
					# (optional)
other_policies	= tsa_policy2, tsa_policy3	# acceptable policies (optional)
digests     = sha1, sha256, sha384, sha512  # Acceptable message digests (mandatory)
accuracy	= secs:1, millisecs:500, microsecs:100	# (optional)
clock_precision_digits  = 0	# number of digits after dot. (optional)
ordering		= yes	# Is ordering defined for timestamps?
				# (optional, default: no)
tsa_name		= yes	# Must the TSA name be included in the reply?
				# (optional, default: no)
ess_cert_id_chain	= no	# Must the ESS cert id chain be included?
				# (optional, default: no)
ess_cert_id_alg		= sha1	# algorithm to compute certificate
				# identifier (optional, default: sha1)


[ alt_names ] 
DNS.1 = gitea
DNS.2 = gitea.home.local
DNS.3 = jenkins
DNS.4 = jenkins.home.local 
DNS.5 = localhost
IP.1 = 127.0.0.1
IP.2 = 192.168.128.65
# End /etc/ssl/jenkins.conf

The self-signed certificate will be used for Nginx later.  Create a self-signed certificate:

openssl req -x509 -nodes -days 3650 -config /etc/ssl/jenkins.cnf -newkey rsa:2048 -keyout /etc/ssl/private/nginx-selfsigned.key -out /etc/ssl/certs/nginx-selfsigned.crt -sha256 -reqexts v3_req

Country Name (2 letter code) [US]:
State or Province Name (full name) [Georgia]:
Locality Name (eg, city) [Evans]:
Organization Name (eg, company) [Home]:
Organizational Unit Name (eg, section) [Office]:
Common Name (e.g. server FQDN or YOUR name) []:gitea.home.local
Email Address []:

Check the certificate you just created:

openssl x509 -in /etc/ssl/certs/nginx-selfsigned.crt -text -noout
openssl x509 -in /etc/ssl/certs/nginx-selfsigned.crt -noout -ext subjectAltName

Create a pkcs12 file, do not leave the password blank:

openssl pkcs12 -export -out jenkins-selfsigned.p12 -inkey /etc/ssl/private/nginx-selfsigned.key -in /etc/ssl/certs/nginx-selfsigned.crt 
Enter Export Password:
Verifying - Enter Export Password:

Use keytool for Java and Jenkins to convert from .p12 to .jks.  Just FYI new password will be added to the Jenkins configuration file:

keytool -importkeystore -destkeystore jenkins.jks -deststoretype PKCS12 -srcstoretype PKCS12 -srckeystore jenkins-selfsigned.p12

Create a directory for the jenkins keystore, and place our keystore in it:

mkdir -p /etc/jenkins
mv /etc/ssl/jenkins.jks /etc/jenkins/

chown -R jenkins: /etc/jenkins
chmod 700 /etc/jenkins
chmod 600 /etc/jenkins/jenkins.jks

Verify the .jks file:

keytool -list -v -keystore /etc/jenkins/jenkins.jks

Backup the Jenkins Configuration file:

cp /etc/default/jenkins /etc/default/jenkins.0

Edit the Jenkins configuration file to add SSL by add the following configuration stanza below:

vim /etc/default/jenkins
HTTP_PORT="-1"
HTTPS_PORT="8443"
HTTPS_KEYSTORE="/etc/jenkins/jenkins.jks"
HTTPS_KEYSTORE_PASSWORD="<your-password>"
JENKINS_ARGS="--webroot=/var/cache/$NAME/war --httpPort=$HTTP_PORT --httpsPort=$HTTPS_PORT --httpsKeyStore=$HTTPS_KEYSTORE --httpsKeyStorePassword=$HTTPS_KEYSTORE_PASSWORD"

Restart Jenkins:

systemctl restart jenkins

Navigate to Jenkins on your browser:
https://192.168.128.65:8443

Configure Nginx as an SSL Termination Proxy

Install Nginx and allow it through the firewall.

apt-get install -y nginx
systemctl status nginx

ufw allow 'Nginx Full'
ufw status

Go to web page and make sure it works:
http://192.168.128.65
http://gitea.home.local

Back up the default sites file:

cp /etc/nginx/sites-available/default /etc/nginx/sites-available/default.0

First we will set up Nginx to proxy for Gitea and Gitea will be the default redirect if you just go to the website:

cat /etc/nginx/sites-available/default | egrep -v ^#
server {
    # gitea.home.local is the default
    listen 80;
    server_name gitea.home.local;
    return 301 https://$server_name$request_uri;
}

server {
    server_name gitea.home.local;
    listen 443 ssl http2;
    include snippets/self-signed.conf;
    include snippets/ssl-params.conf;

    # Log files
    access_log /var/log/nginx/gitea.access.log;
    error_log /var/log/nginx/gitea.error.log;

    # Handle / requests
    location / {
       proxy_pass http://192.168.128.65:3000;
    }
}

Set up Nginx for SSL:

cat /etc/nginx/snippets/self-signed.conf 
ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;


cat /etc/nginx/snippets/ssl-params.conf 
# from https://cipherli.st/
# and https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# Disable preloading HSTS for now.  You can use the commented out header line that includes
# the "preload" directive if you understand the implications.
#add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

Check and make sure the firewall is open:

ufw app list
Available applications:
  CUPS
  Nginx Full
  Nginx HTTP
  Nginx HTTPS
  OpenSSH

Test the Nginx configuration:

nginx -t
nginx: [warn] "ssl_stapling" ignored, issuer certificate not found for certificate "/etc/ssl/certs/nginx-selfsigned.crt"
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Make sure you can login to Gitea:
https://192.168.128.65
https://gitea.home.local

Set up Nginx to proxy for Jenkins:

Backup the Nginx configuration for Gitea:

cp /etc/nginx/sites-available/default /etc/nginx/sites-available/default.gitea.works

Change the file /etc/nginx/sites-available/default to work for Jenkins:

server {
    server_name jenkins.home.local;
    listen 443 ssl http2;
    include snippets/self-signed.conf;
    include snippets/ssl-params.conf;

    location / {
        proxy_set_header        Host $host:$server_port;
        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;

        proxy_pass          http://192.168.128.65:8080;
        proxy_read_timeout  90;
        proxy_redirect      http://192.168.128.65:8080 https://jenkins.home.local;

        proxy_http_version 1.1;
        proxy_request_buffering off;
        add_header 'X-SSH-Endpoint' 'jenkins.home.local:50022' always;
    }
}

Check the Nginx configuration and restart:

nginx -t
systemctl restart nginx

Test that you can login to the Jenkins server.
https://192.168.128.65
https://jenkins.home.local

Backup the Nginx configuration for Jenkins:

cp /etc/nginx/sites-available/default /etc/nginx/sites-available/default.jenkins.works

Now combine the two configuration files:

cat /etc/nginx/sites-available/default  | egrep -v ^#

server {
    server_name jenkins.home.local;
    listen 443 ssl http2;
    include snippets/self-signed.conf;
    include snippets/ssl-params.conf;

    location / {
        proxy_set_header        Host $host:$server_port;
        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;

        proxy_pass          http://192.168.128.65:8080;
        proxy_read_timeout  90;
        proxy_redirect      http://192.168.128.65:8080 https://jenkins.home.local;

        proxy_http_version 1.1;
        proxy_request_buffering off;
        add_header 'X-SSH-Endpoint' 'jenkins.home.local:50022' always;
    }
}


server {
    # gitea.home.local is the default
    listen 80;
    server_name gitea.home.local;
    return 301 https://$server_name$request_uri;
}

server {
    server_name gitea.home.local;
    listen 443 ssl http2;
    include snippets/self-signed.conf;
    include snippets/ssl-params.conf;

    # log files
    access_log /var/log/nginx/gitea.access.log;
    error_log /var/log/nginx/gitea.error.log;

    # Handle / requests
    location / {
       proxy_pass http://192.168.128.65:3000;
    }
}

Check the Nginx configuration and restart:

nginx -t
systemctl restart nginx

Now change Jenkins to listen on 127.0.0.1 and Nginx to redirect to 127.0.0.1.

Edit the file /etc/default/jenkins:

HTTP_PORT=8080
HTTP_HOST=127.0.0.1

JENKINS_ARGS="--webroot=/var/cache/$NAME/war --httpPort=$HTTP_PORT --httpListenAddress=$HTTP_HOST"

Then restart Jenkins:

systemctl restart jenkins

Change the IP address from 192.168.128.65 to 127.0.0.1 in the file /etc/nginx/sites-available/default.

server {
    server_name jenkins.home.local;
    listen 443 ssl http2;
    include snippets/self-signed.conf;
    include snippets/ssl-params.conf;

    location / {
        proxy_set_header        Host $host:$server_port;
        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;

        proxy_pass          http://127.0.0.1:8080;
        proxy_read_timeout  90;
        proxy_redirect      http://127.0.0.1:8080 https://jenkins.home.local;

        proxy_http_version 1.1;
        proxy_request_buffering off;
        add_header 'X-SSH-Endpoint' 'jenkins.home.local:50022' always;
    }
}

Check the Nginx configuration and restart:

nginx -t
systemctl restart nginx

Make sure both Gitea and Jenkins still work.

Integrate Jenkins with Gitea:

Login to Gitea as the administrator user and create an Organization.

Create a team in Gitea and add yourself and jenkins to the team.

Now create a repository  under the Home organization:

Navigate in the Jenkins Dashboard as the Admin user:

Manage Jenkins -> Manage Plugins -> Available -> Search -> gitea

Gitea plugin

Install without restart

Navigate in the Jenkins Dashboard as the Admin user:
Manage Jenkins -> Configure System -> Gitea Servers -> Add
Server URL:
http://192.168.128.65:3000

Click Save

On the Jenkins server create a Jenkins Project:
New Item
Enter an item name
Gitea Organization Folder
Choose:
Organization Folder
OK

Gitea Organization Folder
Display Name: Gitea Integration

Projects -> Repository Sources -> Add ->Gitea Organization
Server will fill in automatically
Credentials
Add
jenkins

Create the repository on your development box and initialize git:

mkdir Test
cd Test
touch README.md
vim Jenkinsfile
pipeline {
    agent any

    stages {
        stage('Do nothing') {
            steps {
                sh '/bin/true'
            }
        }
    }
}
git config --global http.sslverify false
git init
git add .
git commit -m “Added README.md and Jenkinsfile”
git remote add origin https://gitea.home.local/jud/Test.git
git push -u origin master

Check the Jenkins Log:

Make the change in the Gitea configuration file so that the URL shows correctly for a repository:

vim /etc/gitea/app.ini
ROOT_URL         = https://gitea.home.local/
systemctl restart gitea

This entry was posted in Uncategorized and tagged , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s