The operation of a Gitea server with a Let's Encrypt certificate and HAProxy is nicely done on the OPNsense firewall.
Nevertheless: This expansion stage is now suitable for public operation, but it has to be updated and maintained regularly now. Nothing is worse than an outdated and thus vulnerable installation.
Last updated:
This makes the setup look like this:
┌─────────────────────────────┐
│ TrueNAS │
┌──────────────────────┐ │ ┌─────────────────────────┐ │
│ OPNsense │ │ │ jails/git │ │
WAN: 0.0.0.0:80 ─┼─► acme.sh:80 ───────┼─ LAN: 0.0.0.0:3000 ─┼─┼─► gitea │ │
WAN: 0.0.0.0:443 ─┼─► HAProxy:443 │ │ │ │ │
│ │ │ └─────────────────────────┘ │
└──────────────────────┘ └─────────────────────────────┘
With the ACME Client Plugin (os-acme-client) OPNsense is able to create and renew Let's Encrypt certificates automatically. The huge advantage is that we have a central certificate management, don't need a separate management on each internal target system and don't need to configure NAT or other firewall settings.
To get a certificate for your own domain, only a few steps are necessary under "Services - ACME Client". For this we change to the area "Services / ACME Client / Settings" of the OPNsense and set the following checkmarks:
Enable Plugin: JA
Auto Renewal: JA
This activates the plugin and sets the automatic renewal of certificates.
Then we switch to the "Services / ACME Client / Accounts" section and create a new account with the "+" sign.
Enabled: JA
Name: ACCOUNTNAME
E-Mail Address: EMAILADRRESSE
ACME CA: Let's Encrypt [default]
The account must be registered once. On the far right there is a button "Register Account". If the registration is successful, the account will be marked with "OK (registered)".
Next, we specify how the challenge should take place. This is done in the section "Services / ACME Client / Challenge Types". Again, we create a new challenge with the following settings by pressing the "+" sign:
Enabled: JA
Name: GITEAHOSTNAME
Challenge Type: HTTP-01
HTTP Service: OPNsense Web Service (automatic port forward)
Interface: WAN
A new entry is created under "Services / ACME Client / Automations".
Name: Restart HAProxy
Run Command: Restart HAProxy
The last step is to create the certificate. For this we change to "Services / ACME Client / Certificates" and create again a new entry by the "+" sign. In the field "ACME Account" we select the account we just created, in the field "Challange Type" we select the created challange. We select the remaining settings as follows:
Enabled: JA
Common Name: EXTERNALHOSTNAME
ACME Account: ACCOUNTNAME (aus Accounts)
Challenge Type: GITEAHOSTNAME (aus Challenge Types)
Key Length: ec-384
Automations: Restart HAProxy
Now all settings are done and the certificate can be created on the right side with the button "Issue or renew certificate". If successful (this takes a few minutes) the certificate will be marked with "OK" at "Last ACME Status".
Done! The certificate is now renewed fully automatically every 90 days according to the settings.
HAProxy receives the calls for port 443 from the outside, encrypts the connection and forwards it to the internal Gitea server on port 3000. The nice thing is that here again the administration takes place centrally, the certificates can be used without any effort from Let's Encrypt and several services can be provided at the same time on port 443. The difference is made by the called external hostname. This makes it possible that e.g. https://git.domain.de is forwarded to Gitea and https://domain.de to the actual website, although both actually require port 443 on the same external IP address.
The task of HAProxy here is:
The process is: Public Service (EXTERNALHOSTNAME:443) ─► Condition ─► Rule ─► Pool ─► GITEAHOSTNAME:3000
Now to get a forwarding of the EXTERNALHOSTNAME to the internal Gitea, only a few steps are necessary under "Services - HAProxy": In the first step we define a server under "Services / HAProxy / Settings" in the tab "Real Servers". Again, this is done by pressing the "+" button.
Enable HAProxy: YES
Let's start with the "Gitea" service, this gets the following entries:
Name: server_GITEAHOSTNAME
Description: IP Adresse des lokalen Gitea Servers
Type: static
FQDN or IP: GITEAIP
Port: 3000
In the second step we create the "Backend Pools", this we do under "Services / HAProxy / Settings" in the tab "Virtual Services" the entry "Backend Pools".
Name: pool_GITEAHOSTNAME
Description: Pool of local Vaultwarden servers (there is only one)
Servers: server_GITEAHOSTNAME
Now we define the set of rules that determine which incoming connections are forwarded to which service. To do this, we select the "Conditions" entry under "Services / HAProxy / Settings" in the "Rules & Checks" tab and create two conditions:
Name: Gitea host check
Description: Check if the EXTERNALHOSTNAME has been called
Condition type: Host matches
Path Regex: EXTERNALHOSTNAME
These conditions are checked by a rule. We create rules as follows under "Services / HAProxy / Settings" in the "Rules & Checks" tab in the "Rules" entry by pressing the "+" button:
Name: Gitea host rule
Description: Externer Zugriff auf **EXTERNALHOSTNAME** an den richten Server (im Pool) weiterleiten
Select conditions: Gitea host check
Execute function: Use specified Backend Pool
Use backend pool: pool_GITEAHOSTNAME
Finally we create a "Public Services" under "Services / HAProxy / Settings" in the tab "Virtual Services" the entry "Public Services
Name: service_https
Description: Server auf Port 443 der alle externen Anfragen entgegenimmt
Listen Addresses: 0.0.0.0:443
Default Backend Pool: none
Certificates: EXTERNALHOSTNAME (ACME Client)
Default certificate: EXTERNALHOSTNAME (ACME Client)
Cipher List: ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
Cipher Suites: TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
Enable HSTS: YES
HSTS includeSubDomains: YES
Select Rules: Gitea host rule
With "Apply" the configuration is written and the HAProxy service is started.
Please remember to allow port 443 in the firewall.
Now external access to the Gitea is set up and allowed.
Please test the following:
Voilá