OPNsense (firewall) with other stuffs
Install a firewall in VPN
You might consider some VPS without a firewall (UpCloud, Kamatera, etc.), but it is risk hosting anything without firewall protection.
Thus, the solution is to host a firewall, and build servers behind the firewall (although you can use ufw in linux, but I don't think it is good solution)
The following example is created in UPCloud with acceptable protection. (Since the CPU performance and RAM size are too low, some functions will not be used. For example: IDS/IPS, sensei) This setup is also tested on GCP and AWS. For AWS, the SSH user name is ec-user
Since OPNsense lives on FreeBSD, please create instance with FreeBSD 12.2 images (Currently, OPNsense is in FreeBSD 12.2)
You can test creating instance in GCP with following command in GCP shell.
gcloud compute instances create freebsd \
--image freebsd-12-2-release-amd64 \
--image-project=freebsd-org-cloud-dev \
--zone "us-west1-b" \
--machine-type "f1-micro" \
--network "default" --maintenance-policy "MIGRATE" \
--boot-disk-size "29" \
--boot-disk-type "pd-standard" \
--async
gcloud compute ssh freebsd --zone "us-west1-b"
For UpCloud instance, you can use the Console to connect (but it cannot copy command). Please also remember to change boot order to Harddisk first after freebsd setup completed.
1. Install OPNsense on FreeBSD image
pkg install ca_root_nss
pkg install nano
fetch https://raw.githubusercontent.com/opnsense/update/master/src/bootstrap/opnsense-bootstrap.sh.in
nano opnsense-bootstrap.sh.in
Scroll to the bottom of opnsense-bootstrap.sh.in, remove the last "reboot" command in the file and then save. (If you don't do that, you will never be able to connect to the firewall, except UpCloud with Console)
sh ./opnsense-bootstrap.sh.in -r 22.7
2. Pre-config OPNsense
pkg install nano
nano /usr/local/etc/config.xml
Find the "lan" tag in the file, and edit the tag as follow, then save
<lan>
<enable>1</enable>
<if>mismatch0</if>
<ipaddr>dhcp</ipaddr>
<subnet/>
<ipaddrv6/>
<subnetv6/>
<media/>
<mediaopt/>
<track6-interface/>
<track6-prefix-id/>
</lan>
Disable security check in freebsd, so that the mod version of xml file can run
touch /tmp/disable_security_checks
chflags schg /tmp/disable_security_checks
reboot
2.1 Pre-config only for UpCloud
Since FreeBSD instance in UpCloud will recognize 2 NIC device, and only LAN interface will be allowed to connect (as anti-lockout rules apply), we need to swap WAN and LAN interface first.
Control the UpCloud instance with Console, login with ID: root, Password: opnsense choose 1 to assign interface use vtnet1 as WAN and vtnet0 as OPT1
Then connect OPNsense via browser with, https://UpCloud_WANIP
Add a firewall rule in "WAN" for "TCP" from "any" to "This firewall" at port 443
Here is some firewall rules I'm using, 61.X.X.6 is my home IP. I would only allow my home IP to connect OPNsense setting page and SSH.

After adding the rule to WAN, change back vtnet0 as WAN and vtnet1 as OPT1.
Disable OPT1 interface in OPNsense webpage, as it is not our home firewall, we don't have real internal network.

3. Configure OPNsense firewall
connect OPNsense via browser with, https://UpCloud_WANIP LoginID: root Password: opnsense
3A. Add new admin user and disable default root account

You need to change the following, such that it have admin right and can be login via ssh and console

Logout from browser and login from the account you just created, then edit root user and disable it.
3B. Setup Firewall rules
Create Aliases in firewall which blocks known attackers

https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level3.netset
https://cinsarmy.com/list/ci-badguys.txt
https://rules.emergingthreats.net/blockrules/compromised-ips.txt
https://rules.emergingthreats.net/fwrules/emerging-Block-IPs.txt
https://sslbl.abuse.ch/blacklist/sslipblacklist.txt
https://feodotracker.abuse.ch/downloads/ipblocklist.txt
https://lists.blocklist.de/lists/all.txt
https://www.dan.me.uk/torlist/
https://reputation.alienvault.com/reputation.generic
Then create firewall rule, below is the firewall rule I'm using. For GCP and AWS, it is actually LAN firewall rule. Please ignore Wire net and Wireguard net, as we have not created VPN yet.

Then we will add a cron job to update blocklist everyday

3C. Allowing SSH connection
Since UpCloud Console cannot paste text, we still need to allow SSH connection in OPNsense. We can disable it after xray setup completed.
Since we wound like xray use port 443, we will change OPNsense to use HTTP.
And we don't want others to access OPNsense page freely, we will also change OPNsense to port 8080 (although you can work another way, change the xray fallback port from 80 to others and also change nginx port)

We also need to allow SSH to access sudo with password

After apply for the change, please use http://UpCloud_WANIP to access the configuration page. We will be able to access it again via HTTPS after xray, DDNS and ACME setup completed. Please also remember to disable the port rule for 80 and 22 after these setup.
3D. Setting DNS-over-TLS and DNS blocklist (with AdGuardHome)
I have removed the Unbound setting right now. Will add back my home setting of unbound later. (If I have time)
Since there is way to install AdGuardHome in OPNSense, we can add more lists with little RAM usage.
Connect to server via SSH. After login, choose 8 for shell.
sudo -i
Add minigmail repository
fetch -o /usr/local/etc/pkg/repos/mimugmail.conf https://www.routerperformance.net/mimugmail.conf
Perfom package update in Opnsense, then install os-adguardhome-maxit

Refresh (F5) OPNSense page, then start AdGuardHome

Setup firewall rule to allow you to control AdGuardHome page
TCP Protocol, from "Your IP" any port, to WAN address port 3000

Change Unbound Setting to listen different port, and tick Register DHCP static mappings

Setup DOT in unbound, Use system Namespaces should be unchecked Note: this one is the secure DNS provided by Cloudflare If you want normal one, use following 1. Address: 1.1.1.1, Port: 853, Hostname: 1dot1dot1dot1.cloudflare-dns.com 2. Address: 1.0.0.1, Port: 853, Hostname: 1dot1dot1dot1.cloudflare-dns.com

Access AdGuardHome from browser

Setup AdGuardHome upstream, 127.0.0.1:5353

After your finished 3H, if you don't want to open http interface You can set encryption as following, then change the firewall rule

You also need to add Automation in acme if you finish 3H

For other blocklist settings, check Debian side
Remark: config file of AdGuardHome is located in: /usr/local/AdGuardHome/AdGuardHome.yaml
3E. Setup Nginx
First, we will setup error handling page


Everything in Status Codes should be Selected.
For Page Content, Code is as follow:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Error</title>
</head>
<body>
<h1>Error</h1>
<p>Sorry, but something went wrong.</p>
</body>
</html>
Then we will configure HTTP server, since we will not host HTTPS server directly, it is fine for not configuring TLS cert.


Finally, we will Locate the folder to host as webpage and start the webserver



Then we will create a page to host the web server (You can host a real page if you want)
cd /srv/web_application1
nano index.html
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
3F. Setup Xray
I only tested cron job and it auto start after reboot. You might need to setup again after firmware update. Connect to server via SSH. After login, choose 8 for shell.
sudo -i
Type the password again, then generate Cloudflare warp config
pkg install wget
mkdir /usr/local/wgcf
cd /usr/local/wgcf
wget https://github.com/ViRb3/wgcf/releases/download/v2.2.15/wgcf_2.2.15_freebsd_amd64 -O wgcf
chmod 777 wgcf
./wgcf register
./wgcf generate
cat wgcf-profile.conf
Copy the Privatekey and Public key that will use later
mkdir /usr/local/xray
cd /usr/local/xray
wget https://github.com/XTLS/Xray-core/releases/download/v1.7.2/Xray-freebsd-64.zip
unzip Xray-freebsd-64.zip
rm Xray-freebsd-64.zip
chmod 555 xray
chmod 664 geosite.dat geoip.dat
Then create the config file for xray. Please copy the code to notepad, edit it and copy back to shell There is an assumption in the code, in cert location, I assume that the ddns is a.bname.com, please change it to your ddns name. Please generate ID using UUID generator
nano config.json
Following config applies to Xray 1.7.2
Config description: Default using vless, xtls-rprx-vision, fallback to webpage if invalid If path /fallws is provided, fallback to use ws, and it only accept proxy protocol connection (for example Cloudflare CDN) If destination is CN domain or CN IP, use Cloudflare warp for outbound
Replace following values: 90000000-0000-0000-0000-00000000000a : UUID you generated (2 instance) /fallws : the folder you name to tell xray fallback using ws/CDN (2 instance) UI0000000000000000000000000000000000000u/Wk= : PrivateKey in 5 bm000000000000000000000000000000000000000yo= : PublicKey in 5
{
"log": {
"loglevel": "none"
},
"dns":{
"servers":[
"localhost"
],
"queryStrategy":"UseIPv4"
},
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"domain": [
"geosite:category-ads-all"
],
"outboundTag": "block"
},
{
"type": "field",
"domain": [
"geosite:cn"
],
"outboundTag": "wireguard-1"
},
{
"type": "field",
"ip": [
"geoip:cn"
],
"outboundTag": "wireguard-1"
},
{
"type": "field",
"ip": [
"geoip:private"
],
"outboundTag": "block"
}
]
},
"inbounds": [
{
"port": 443,
"protocol": "vless",
"settings": {
"clients": [
{
"id": "90000000-0000-0000-0000-000000000000",
"flow": "xtls-rprx-vision"
}
],
"decryption": "none",
"fallbacks": [
{
"alpn": "http/1.1",
"dest":81
},
{
"path": "/fallws",
"dest": 1234,
"xver": 1
},
{
"alpn": "h2",
"dest": 82
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"minVersion":"1.3",
"alpn": [
"h2",
"http/1.1"
],
"certificates": [
{
"certificateFile": "/var/etc/acme-client/home/a.bname.com/fullchain.cer",
"keyFile": "/var/etc/acme-client/home/a.bname.com/a.bname.com.key",
"ocspStapling": 3600
}
],
"rejectUnknownSni": true
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
},
{
"port": 1234,
"listen": "127.0.0.1",
"protocol": "vless",
"settings": {
"clients": [
{
"id": "90000000-0000-0000-0000-000000000000",
"level": 0
}
],
"decryption": "none"
},
"streamSettings": {
"network": "ws",
"security": "none",
"wsSettings": {
"acceptProxyProtocol": true,
"path": "/fallws"
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
}
],
"outbounds": [
{
"protocol": "freedom",
"settings": {
"domainStrategy": "UseIPv4"
},
"tag": "direct"
},
{
"protocol": "wireguard",
"settings": {
"secretKey" : "UI0000000000000000000000000000000000000u/Wk=",
"peers": [
{
"publicKey": "bm000000000000000000000000000000000000000yo=",
"endpoint": "engage.cloudflareclient.com:2408"
}
]
},
"tag": "wireguard-1"
},
{
"protocol": "blackhole",
"tag": "block"
}
]
}
Add a file for setting xray as service
nano /usr/local/etc/rc.d/xray
#!/bin/sh
# PROVIDE: xray
# REQUIRE: netif NETWORKING ipmon ipfw netwait
# BEFORE: LOGIN
# KEYWORD:
. /etc/rc.subr
name="xray"
rcvar=xray_enable
start_precmd="xray_checkconfig"
restart_precmd="xray_checkconfig"
reload_precmd="xray_checkconfig"
configtest_cmd="xray_checkconfig"
command="/usr/local/xray/xray"
command_args="&"
required_files=/usr/local/xray/config.json
extra_commands="reload configtest"
load_rc_config "xray"
xray_configfile="/usr/local/xray/config.json"
xray_flags="-config ${xray_configfile}"
xray_checkconfig()
{
eval ${command} ${xray_flags} -test
}
run_rc_command "$1"
Add another file for Cron to handle xray service job
nano /usr/local/opnsense/service/conf/actions.d/actions_xray.conf
[start]
command:/usr/local/etc/rc.d/xray start
type:script
message:starting xray
[restart]
command:/usr/local/etc/rc.d/xray restart
type:script
message:restarting xray
description:Restart Xray service
[stop]
command:/usr/local/etc/rc.d/xray stop
type:script
message:stopping xray
[status]
command:/usr/local/etc/rc.d/xray status
type:script_output
message:get xray status
Then make both files able to run, and make the xray service able to start
chmod +x /usr/local/etc/rc.d/xray
chmod +x /usr/local/opnsense/service/conf/actions.d/actions_xray.conf
nano /etc/rc.conf
Add following line to script, then save
xray_enable="YES"
Add a cron job to restart xray everyday

3G. Setup DDNS
Note: we use os-ddclient instead of os-dyndns now, setting is similar. I will update it later
Install acme and dyndns plugin, you can also install wireguard if you want to setup too. After all setup is done, Click OPNsense logo in top left corner to refresh the page.

You can setup your own ddns service if you know the username and password to type. For someone using freemyip, example is here

For someone use Cloudflare, example is as below Username is your Cloudflare account email, Password is the Global API, host name is the target dns record, you can create an non-proxied A record with 8.8.8.8 first.

After creating the DDNS client, restart the client by clicking below button. Check if you can resolve the ip using ping

When this is done, create a cron job to update DDNS every 15 minutes.

3H. Acme client
Create a Let's Encrypt account in Let's encrypt service, then click the following button to register

If you are not using Cloudflare, please setup as follow, this require to open port 80 in firewall

If you are using Cloudflare, please setup as below, you can also choose using Email with Global API or Account ID with API Token (Zone.Zone.Read, Zone.DNS.Edit, All Zone). My example is to use API Token with Account ID.

Then Setup the detail of the Cert creation, after saving the setting, try Issue/Renew Cert and check the LogFile to see how it runs

If everything succeed, setup the plugin scheduler

Then setup a cron job to reboot the firewall every month. Such that the cert in xray can be updated.

From this point, everything are setup except WireGuard. Please reboot OPNsense to check rather xray works.
3I. WireGuard
Assume that you have installed the Package already
It is recommended to generate keys in SSH to avoid misconfiguration.
mkdir /usr/local/wgkeys
cd /usr/local/wgkeys
umask 077; wg genkey | tee privatekey | wg pubkey > publickey
umask 077; wg genkey | tee private_client_key | wg pubkey > public_client_key
umask 077; wg genpsk > presharedkey
cat privatekey
cat publickey
cat private_client_key
cat public_client_key
cat presharedkey
rm -r ../wgkeys/
Setup Endpoint, then local. After all setup, go to general to start Wireguard.


There will be a new interface appear,

After adding the interface, you need to enable the interface by click on the link and tick enable.
There should be two net interface in Firewall->Rules, configure both interface as follow

Setup a cron job to restart unbound DNS after firewall restarted. As wireguard will turn on after unbound is up, Unbound DNS will not listen to requests of Wireguard, we need to restart DNS services once.

Restart OPNsense, when you find the CPU loading is lowered. Restart Unbound DNS service. Then everything should work.
3J. Configuration Backup to Google Drive
You can backup the configuration to Google Drive https://docs.opnsense.org/manual/how-tos/cloud_backup.html
After setting the Cloud Backup, you can create a cron job to backup configuration daily.
3K. Setup IKEv2/IPSEC VPN
This session will use ESP-MSCHAPV2. Since 23.1, OPNsense is planning to replace the Lagacy method with current StrongSwan config, I might update this part to new method if I have time.
Setting up Loopback Virtual IP
Since there is no gateway in IPSEC, we will create a loopback interface for IPSec to use local DNS.
Generate CA
We will use self-signed cert for IPSec, I usually ECC certificate if available, you can use RSA if you want. Values in Distinguished name can be change to anything that you want, also for Descruptive name
Download the crt certificate of CA after you save it, you will need it to setup your PC/phone.
Generate Server certificate
Below picture is the server certification Remember to change a.bname.com in Common Name and Alternative Names to your DDNS name, they will be checked with you PC/phone setting when you try to connect

Setting up PSK for IPSec
This is the login ID and password for the IPSec
Setting up Mobile Clients
DNS is the Loopback Virtual IP you have created Virtual IPv4 Address Pool is the virtual subnet you want to assign to IPSec, please don't assign any subnet you are using in DHCP

Setting up Tunnel
After save, Press "Create Phase 1" in this screen to create tunnel

Remember to change a.bname.com to your DDNS name here
Setting up Phase 2
After saving Phase 1, you must create Phase by clicking the button as shown below

0.0.0.0/0 here means when a client connected to this tunnel, all traffic of that client will pass through this tunnel
Apply setting after you saved all settings
Setting up DNS service
If you are running AdGuardHome in OPNsense, please restart AdGuardHome If you are running unbound DNS only, please Allow the Virtual subnet to access unbound DNS


Open firewall port
Android Setup
check following link
Limitation of lower-end VPS
The performance of lower-end VPS is close to a desktop PC with Celeron installed. It run out of CPU resources even with minimum setting, having about 400Mbps maximum. When having IDS/IPS on, the speed lowered to 25Mbps. My home router is using i3-8130U (I have only assigned 50% CPU resources to OPNsense VM), 10GB Ram. I have enabled not only DNS Blocklists, firewall, but also IDS/IPS to detecting WAN attacks. Sensei (Layer 7 Firewall) to taking care of LAN interfaces. It is still able to run 1Gbps under VPN. That's I says this is the minimum requirement for a firewall. As it only block ports, and known attackers. Doesn't detect attacking behavior from unknown IP (especially China). Although it is better than nothing.
Below is the capture of my OPNsense hosted in UpCloud.

One IP is keep attacking port 22 is an IP from China. Some IP are from Russia and Netherlands. So, when you finished setup. Please remember to hide port 22. Or set it only open to your home IP. As you never know any new attacker is attacking port 22 or other port but not showing in this list.
Here is the IDS/IPS log of my home router

I have seen someone trying to attack port 443 and 80. But they are blocked by IDS.
Last updated
Was this helpful?