Scenario:

When you have only one interface connected and you add another interface to the same machine (in my case VLAN interface), there will be 2 default routes: one for each interface, in my test lab ens18 and ens19.50. Both will initially have a default route metric of 100. The metric is a measure of route priority, where a higher metric means lower priority.

ens18 will be used for server management and ens19.50 will be used for qBittorent Docker container. I want to mount a NAS share to the host, to which a qBittorent Docker container would have access to. Because both routes have the same metric, we don’t know from which interface a samba share would be mounted. I don’t want my samba share to be mounted via management interface, because all traffic from torrents to NAS will go through management interface, and we don’t want that. Firstly ens18 is only 1 Gbps while ens19.50 is 10 Gbps and secondly, traffic flow from ens19.50 to ens18 is forbidden on my firewall, so Docker container wouldn’t be able to save files.

Tested on Ubuntu server 24.04 LTS.

Goals:

  • ens18: Used for server management.
  • ens19.50: Used for a qBittorrent Docker container.
  • Mount a NAS share to the host, accessible by the qBittorrent Docker container directly.

Problem:

With both routes having the same metric, the system might mount the Samba share via the ens18 management interface. This is not desirable because:

  1. Bandwidth Limitation: ens18 is only 1 Gbps, while ens19.50 is 10 Gbps.
  2. Firewall Restrictions: Traffic flow from ens19.50 to ens18 is forbidden on my firewall, preventing the Docker container from saving files to the NAS if it were mounted via ens18. That means, torrent traffic would flow from ens19.50 to NAS via ens18, because samba share is mounted via ens18.

Solution:

To ensure that traffic to the NAS goes through the 10 Gbps ens19.50 interface, we will:

  1. Change the Metric: Adjust the metric for the default route on ens19.50 to 200, making it a lower priority for general traffic.
  2. Add a Specific Route: Add a specific route for the NAS (192.168.20.5) via ens19.50.

Network Configuration:

  • ens18: untagged interface (management)
    • IP: 172.16.210.105
    • Mask: 255.255.255.0
    • Gateway: 172.16.210.1
  • ens19.50: created on trunk interface (VLAN50 – torrent traffic) 
    • IP: 192.168.50.100
    • Mask: 255.255.255.0
    • Gateway: 192.168.50.1
    • Docker network type is macvlan
  • NAS server: (torrent flow destination)
    • IP: 192.168.20.5

Ens18 and ens19.50 both receive their IP configuration via DHCP server. I prefer creating static DHCP reservation on my firewall than entering IPs manually to each device.

Steps:

  1. Understand Route Metrics:
    • Each route has a metric.
    • Lower metric means higher priority.
    • We will change the metric of the default route for ens19.50 to 200, so ens18 will be preferred for all traffic except 192.168.20.5.
  2. Edit Netplan Configuration:
    • We will edit the netplan configuration to set the route metrics and add a specific route for 192.168.20.5.

Instructions:

  1. Open the Netplan Configuration File:
    • Open a terminal.
    • Use a text editor to edit the netplan configuration file /etc/netplan/vlans.yaml.
  2. Configure the Interfaces and Routes:
    • Add the following configuration:

network: version: 2 ethernets: ens19: dhcp4: no ens18: dhcp4: true vlans: ens19.50: id: 50 link: ens19 dhcp4: true dhcp4-overrides: route-metric: 200 routes: - to: 192.168.20.5/32 via: 192.168.50.1

Explanation:

  • ethernets: Defines the parent interface ens19 and the primary interface ens18.
  • vlans: Defines the VLAN interface ens19.50 with VLAN ID 50.
    • dhcp4-overrides: Sets the route metric for ens19.50 to 200.
    • routes: Adds a specific route for 192.168.20.5 via 192.168.50.1
  1. Apply the Configuration:
    • Apply the netplan configuration with the following command:

netplan apply

  1. Verify the Routing Table:
      • Check the routing table to ensure the configuration is correct:

    ip route

      • You should see:

    default via 172.16.210.1 dev ens18 proto dhcp src 172.16.210.105 metric 100 default via 192.168.50.1 dev ens19.50 proto dhcp src 192.168.50.100 metric 200 192.168.50.1 dev ens19.50 proto dhcp scope link src 192.168.50.100 metric 200

    Result:

    • Traffic to 192.168.20.5 will go via ens19.50 (VLAN50).
    • All Other Traffic: Will go via ens18 because its metric is 100, which has higher priority over ens19.50 with a metric of 200.

    When we mount the share, we can see in our pfsense firewall, the connection was successfully established from 192.168.50.100 (ens19.50) to 192.168.20.5 (NAS)

    Notes:

    • The dhcp4-overrides section in the netplan file allows you to specify DHCP options, including setting the route metric.
    • Specific routes added in the routes section ensure that traffic to 192.168.20.5 uses the desired interface.

    What is Policy-Based Routing?

    Policy-based routing (PBR) is a technique used to make routing decisions based on policies set by network administrators. These policies can be based on various criteria such as source or destination IP addresses, protocols, or traffic types. In this example, we are using PBR to route traffic to a specific IP address (192.168.20.5) through a specific interface (ens19.50).

    Starting with version 8.5, Cisco has introduced an innovative feature to its Wireless LAN Controller (WLC): the Identity Pre-Shared Key, or iPSK. This functionality allows multiple devices, especially those unable to support WPA Enterprise authentication (802.1x), to connect to the same SSID but with unique credentials and configurations. This can be particularly useful in diverse device environments, such as those involving various IoT devices.

    A common application of iPSK includes setting up distinct network access configurations for different devices on the same network. Here are two practical scenarios:

    Scenario 1: All devices connect to the same SSID using the same Wi-Fi password, yet they are assigned to different VLANs based on their identity.

    Scenario 2: Devices connect to the same SSID with distinct Wi-Fi passwords, and can either be on the same VLAN or separate VLANs depending on the configuration.

    While Scenario 1 is ideal for simplicity and home networks, may not offer the same level of security as Scenario 2. It is perfectly suited for home networks where the primary goal is to segment devices into different VLANs using the same password. This setup simplifies management without significantly compromising security, making it a practical choice for less complex environments.

    Scenario 2 is the optimal security configuration and offers the highest level of security. In this setup, each device is assigned its own unique password. This is particularly beneficial because if a device is compromised, the impact is isolated. You only need to revoke or change the password for the affected device without disrupting the connectivity of other devices on the network.

    Before diving into the specific scenarios of iPSK deployment, ensure you have the following foundational elements configured and operational:

    – WLC Controller and pfSense RADIUS Server Connection: Ensure that your Wireless LAN Controller (WLC) and pfSense RADIUS server are properly connected and communicating. This setup is crucial for authenticating devices on your network using iPSK.

    – VLAN Functionality: Configure VLANs on both the pfSense and WLC controller. On the pfSense, this involves setting up VLAN tagging and defining VLAN interfaces. On the WLC controller, VLANs should be configured under the ‘Interfaces’ section. Proper VLAN configuration is essential for segmenting network traffic and enhancing security.

    Having these elements in place will provide a solid foundation for implementing the iPSK scenarios described, ensuring a smoother and more secure deployment.

    My lab setup was done on Cisco WLC 2504 (8.5.105.0) and PfSense (2.7.2).

    Setting Up Scenario 1: Single Password with VLAN Assignment on the same SSID

    To configure iPSK with VLAN assignments using the same password for all devices, follow these steps on your pfSense and WLC controller:

    1 Configure Users in pfSense:

    • Navigate to Services -> FreeRADIUS -> Users on your pfSense interface.
    • Create a new user entry where both the username and password are the MAC address of the client device, formatted without separators. For instance, if the MAC address is 80:39:8c:3e:ff:da, you would use 80398c3effda for both the username and password. If you’re using Android clients, make sure you disable randomize MAC option in wifi settings and use Phone MAC instead.

    2 Assign VLANs:

    • When creating the user, also assign the desired VLAN to this username. This VLAN is where the device will be placed upon successful authentication.


    3. configure WLAN in WLC for scenario 1:

    To set up the WLAN that will be used with iPSK, follow these detailed steps within your Cisco Wireless LAN Controller (WLC):

    3.1 Create a New WLAN:

    • Navigate to the WLANs section in the WLC interface.
    • Click on Create New WLAN to start the setup process.

    3.2 General Settings:

    • In the General tab, provide a Profile Name and the SSID (Service Set Identifier) for your new WLAN.
    • Make sure to set the WLAN status to Enabled to activate it upon creation.

    3.3 Security Settings:

    • Go to the Security tab and then to the Layer 2 sub-tab.
    • Enable MAC Filtering to restrict access based on the MAC addresses of client devices.
    • Additionally, enable the PSK (Pre-Shared Key) option to set a universal Wi-Fi password for all devices. Directly beneath the PSK settings, enter the Wi-Fi password you desire in the PSK Format field.

    3.4 Radius server

    • Go to the security tab and then to the AAA Server sub-tab
    • Under Server 1, select your radius server, which should be already set from required prerequisites
    • Apply settings and try to connect the client

    3.5 Advanced settings

    • Go to Advanced tab and enable Allow AAA Override. This means, radius server will push settings like VLAN, QOS and other optional stuff.

    Authentication workflow in scenario 1 is:

    • When a client attempts to connect to the Wi-Fi network, the WLC will initially check the Wi-Fi universal password (PSK).
    • After the PSK validation, the WLC will forward the authentication request to the pfSense RADIUS server to verify if the client’s MAC address matches the username and password configured in RADIUS.
    • If a match is found, the user is authorized and placed into the correct VLAN. If no matching user entry exists for the MAC address, the Wi-Fi connection attempt will fail.
    • If the VLAN specified for a client in the pfSense RADIUS server does not exist on the Cisco WLC, or if it is not properly configured in the WLC settings, the client device will not be assigned to the intended VLAN. Instead, the device will default to the VLAN associated with the WLC’s default interface for that particular WLAN.

    Setting Up Scenario 2: Unique Passwords with VLAN Assignment on the same SSID

    This scenario allows each user to have a unique password, enhancing security by isolating potential breaches to individual devices. Follow these steps to configure unique passwords per user in pfSense using FreeRADIUS:

    2.1 Edit User Configuraton:

    • Navigate to Services -> FreeRADIUS -> Users in the pfSense interface.
    • Select and edit the user configuration set up in Scenario 1.

    2.2 Configure Additional RADIUS Attributes:

    • Scroll to the bottom of the user settings to find the field labeled Additional RADIUS Attributes (REPLY-ITEM).
    • Add Cisco AV Pairs to define unique passwords for each device
    • Enter Cisco-AVPair = “psk-mode=ascii” to specify that the password is in plain text.
    • Add Cisco-AVPair += “psk=client_unique_wifi_cleartext_password” where client_unique_wifi_cleartext_password is the unique password you assign to this user. Replace client_unique_wifi_cleartext_password with the actual password you intend to use.
    • The whole entry should look like: Cisco-AVPair = “psk-mode=ascii”,Cisco-AVPair += “psk=client_unique_wifi_cleartext_password”

    2.3 Save the configuration

    2.4 Connect to the Network

    • Attempt to connect a device using the new unique password set in the RADIUS attributes.
    • Ensure that the device’s MAC address randomization feature is turned off to avoid connection issues due to unrecognized MAC addresses.

    Authentication workflow in scenario 2 is:

    • When a client attempts to connect to the Wi-Fi network with Radius password, the WLC will forward the authentication request to Radius to validate user.
    • If a match is found, the user is authorized and placed into the correct VLAN. If no matching user entry exists for the MAC address, the Wi-Fi connection attempt will fail.
    • If the VLAN specified for a client in the pfSense RADIUS server does not exist on the Cisco WLC, or if it is not properly configured in the WLC settings, the client device will not be assigned to the intended VLAN. Instead, the device will default to the VLAN associated with the WLC’s default interface for that particular WLAN.

    Steps to configure fallback VLAN in FreeRADIUS on PfSense:

    In both Scenario 1 and Scenario 2, you need to have a valid RADIUS user. If you try to use the universal WiFi password defined in the WLC, it won’t work. To use a fallback VLAN with a universal password for users not defined in RADIUS, you need to add additional parameters in the FreeRADIUS configuration. SSH into your pfSense system and open the file at /usr/local/etc/raddb/users.

    Add this to the end of the file:

    DEFAULT Auth-Type := Accept
    
        Tunnel-Type = VLAN,
        Tunnel-Medium-Type = IEEE-802,
        Tunnel-Private-Group-ID = "665"

    Change “665” to your desired fallback VLAN. Save the file and restart the Radius server. Ensure that this entry is always at the end of the file when adding new users.

    In your PfSense GUI, it should look something like this:

    Now, you can connect a device without a RADIUS user to the WiFi using the universal password. It will default to VLAN 665.

    Caveat: editing config files directly from shell is tricky for PfSense, because everytime you change a config via GUI, config edite from shell will get rewritten, and all your changes will be gone. The same will happen with reboot. If you wan’t to make a change permanent, you should make a cronjob that adds manual config at reboot, or edit main template file radius.inc found at /usr/local/pkg/freeradius.inc.

    Example:

    • Connecting with a user defined in RADIUS will result in a successful connection to WiFi with the VLAN assigned to that user.
    • Connecting to WiFi with the universal password will result in a successful connection with the VLAN defined under DEFAULT Auth-Type := Accept, in this case, VLAN 665.

    You can use both WLC universal password and radius user password to connect to WiFi, depending on your needs. Ensure your fallback VLAN is securely configured.

    References:
    https://www.linkedin.com/pulse/shared-ssid-ciscos-identity-psk-freeradius-alexandru-panaitescu/
    https://www.wifireference.com/2017/12/10/cisco-identity-psk-what-is-it-and-how-is-it-configured/
    https://www.cisco.com/c/en/us/support/docs/security-vpn/remote-authentication-dial-user-service-radius/116291-configure-freeradius-00.html
    https://goodwi.fi/posts/2023/09/ipsk-no-ise-freeradius/

     

    If you have your mailinabox installation behind HTTP reverse proxy, such as nginx proxy manager for example, mailinabox will send you emails each day with subject TLS Certificate Provisioning Result, containing errors.

    That’s because it fails to install let’s encrypt certificates. Your web certificates are handled by your reverse proxy, so you don’t need mailinabox to do that. To disable certificate provisioning, open file:
    /root/mailinabox/management/daily_tasks.sh and comment out this line:

    management/ssl_certificates.py -q 2>&1 | management/email_administrator.py “TLS Certificate Provisioning Result”

    Restart service:

    systemctl restart mailinabox

    Did you install the Mailinabox (Mail-in-a-Box) solution and discover that your admin interface is publicly accessible? Me too, and there are no settings to limit this via GUI. My goal was to access admin interface only via my local network IP.

    The Mail-in-a-Box web server runs on Nginx, and limiting IP access in Nginx is pretty simple. First, you need to find the config file. The default location in Mail-in-a-Box is /etc/nginx/conf.d/local.conf. But this file is overwritten if any changes are detected. So you actually need to modify two files, /etc/nginx/conf.d/local.conf and the template config file /root/mailinabox/conf/nginx-primaryonly.conf which Mail-in-a-Box uses to populate local.conf file. Open both files and modify the following section:

    location /admin/assets {
                    alias /usr/local/lib/mailinabox/vendor/assets;
            }
            rewrite ^/admin$ /admin/;
            rewrite ^/admin/munin$ /admin/munin/ redirect;
            location /admin/ {
                    proxy_pass http://127.0.0.1:10222/;
                    proxy_set_header X-Forwarded-For $remote_addr;
                    add_header X-Frame-Options "DENY";
                    add_header X-Content-Type-Options nosniff;
                    add_header Content-Security-Policy "frame-ancestors 'none';";
            }
    

    Change it to:

    location /admin/assets {
                    alias /usr/local/lib/mailinabox/vendor/assets;
            }
            rewrite ^/admin$ /admin/;
            rewrite ^/admin/munin$ /admin/munin/ redirect;
            location /admin/ {
                    proxy_pass http://127.0.0.1:10222/;
                    proxy_set_header X-Forwarded-For $remote_addr;
                    add_header X-Frame-Options "DENY";
                    add_header X-Content-Type-Options nosniff;
                    add_header Content-Security-Policy "frame-ancestors 'none';";
                    allow 192.168.60.2;
                    deny all;
            }
    

    We added the line “allow 192.168.60.2;” to grant admin access to the IP 192.168.60.2 and the line “deny all;” to deny access to everyone else. If you’re not running a reverse proxy in front of Mail-in-a-Box, you’re done. Be sure to change 192.168.60.2 to your local IP.

    Save the changes and reload Nginx with the following command:

    sudo service nginx reload

    If you’re running a reverse proxy in front of Mail-in-a-Box, such as nginx proxy manager, you need to add some more settings to the Mail-in-a-Box nginx.conf file. When the reverse proxy passes requests to Mail-in-a-Box, it uses its own IP (the IP of the reverse proxy), so each request appears to come from the reverse proxy IP instead of the client’s IP. This would result in blocking all clients.

    To circumvent this and obtain the correct client’s IP, you need to enable the Real IP Header module in the Mail-in-a-Box nginx.conf file. First open another template file /root/mailinabox/conf/nginx.conf, find this section and modify it:

    # The secure HTTPS server.
    server {
            listen 443 ssl http2;
            listen [::]:443 ssl http2;
            server_name $HOSTNAME;
    ...
    

    Change it to:

    # The secure HTTPS server.
    server {
            listen 443 ssl http2;
            listen [::]:443 ssl http2;
    
            real_ip_header X-Forwarded-For;
            real_ip_recursive on;
            set_real_ip_from 0.0.0.0/0;
    
            server_name $HOSTNAME;
    ...
    

    Now open /etc/nginx/conf.d/local.conf and find this section:

    # The secure HTTPS server.
    server {
            listen 443 ssl http2;
            listen [::]:443 ssl http2;
            server_name yourdomain.com;
    ...
    

    Change it to:

    # The secure HTTPS server.
    server {
            listen 443 ssl http2;
            listen [::]:443 ssl http2;
    
            real_ip_header X-Forwarded-For;
            real_ip_recursive on;
            set_real_ip_from 0.0.0.0/0;
    
            server_name yourdomain.com;
    ...
    

    Be sure to change yourdomain.com to your own domain.

    Save the changes and reload Nginx with the following command:

    sudo service nginx reload

    Try accessing the admin interface from your local IP and then from another IP. Your local IP should have access, but other IPs should receive a forbidden error.

    Here’s an example of the access log:

    tail -f /var/log/nginx/access.log
    192.168.60.2 - - [16/Jun/2023:17:59:15 +0200] "GET /admin HTTP/1.1" 200 39073
    188.196.15.222 - - [16/Jun/2023:17:59:18 +0200] "GET /admin HTTP/1.1" 403 180
    

    We can see that my local IP received a response code of 200, indicating a successful request, while the second IP received a response code of 403, meaning the server understood the request but refused to authorize it.

    We modified the following files:

    Running config files:
    /etc/nginx/conf.d/local.conf

    Template files:
    /root/mailinabox/conf/nginx-primaryonly.conf
    /root/mailinabox/conf/nginx.conf

    Quick notes, how to add villa door station to hik-connect app, since Hikvision documentation is all over the place. We are assuming you already have network connectivity to the device.

    Goal: add villa door station to hik-connect app, so you can remote view your cameras on mobile app

    1. The device I’m configuring is DS-KV8113-WME1(B)

    2. You will need serial number. It’s located on the back of device, there is a sticker. Alternatively, login to your device via web interface. Go To configuration, System Settings, and there is a section Serial No. Select text and scroll with your mouse to the right. The actual serial number is last 9 characters:

    3. Create account and login at https://www.hik-connect.com/

    4. Enable platform access on your device. Go back to your device via web browser and go to Configuration, Network, Advanced, Platform Access. Click Enable, and setup Stream Encryption/Encryption Key. This is the part where Hikvision documentation is lacking. When you are going to add device to hik-connect app, you will be asked for serial number and verification code. Some devices have verification code written on the label, but my device doesn’t. The verification code is Stream Encryption/Encryption Key.

    5. Go back to https://www.hik-connect.com/ and click Add. You will be asked to enter serial number and verification code. If everything is done right, your devices will be online.

    6. Download hik-connect mobile app. I’m using Android. Here lies another CAVEAT. Don’t download app from Google Playstore, because they are not updating the app anymore. Hikvision has it’s own app store at: https://appstore.hikvision.com/. Download Hik-Connect – for End user, install it, login to your hik-connect account and you’re done. You should be able to view and operate your cams via their cloud remotely.

    A note of caution. Don’t put your camera in your bedroom, this goes on Hikvision cloud and they can probably spy on you, it’s a Chinese product nevertheless. Extra points if you put your device on separate VLAN and isolate it from the rest of your network.

    Cisco DNA center currently lacks a feature to export all inventory. You can’t export serial numbers for power supplies and network modules. This bash script is very simple and primitive, it connects to Cisco device via SSH and collects inventory data. If you have a lot of devices, this will take a lot of time. You need to modify this script for parallel ssh connections if you have more than 100 devices. For more info, read the script comments.

    #!/bin/bash
    
    # SSH credentials for Cisco devices
    # For security reasons, make sure the user is read only capable
    user=CiscoUsername
    password=CiscoPassword
    
    # Path to file where IPs of devices are stored (one IP per line)
    file=devices.txt
    
    # Mail settings
    mailrelay="smtp=some.mail.server:25"
    sender=no-reply@somedomain.com
    mailto=some.user@somedomain.com
    mailsubject="inventory bash exporter - C9K2,C9K3,C9K5 devices"
    
    # Path to output file (exported inventory file)
    results=results.txt
    
    # Cleanup from before
    
    rm -f "$results"
    
    # Check if necessary files exist
    if [ ! -f "$file" ]; then
        echo
        echo "ERROR: Missing file with IP addresses. Exiting ..."
        echo
        exit 1
    fi
    
    lines=$(cat $file)
    
    for line in $lines
    do
            # Connect to device, read hostname and append output to file. I filter hostname by "-SDA-", because each device
            # contains "-SDA-" in hostname, in my case. You need to modify this to your own needs.
            sshpass -p "$password" ssh -t -q -o ConnectTimeout=5 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null\
            "$user"@"$line" 'show run | i hostname' | grep "\-SDA\-" | sed 's/=//g' | sed 's/\//g' | sed 's/ //g' >> "$results"
    
            # Connect to device, read inventory, filter output to get desired results (you can modify this to your own needs)
            # and append output to file. I filter out SFP modules, FAN trays, Stack modules.
            sshpass -p "$password" ssh -t -q -o ConnectTimeout=5 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null\
            "$user"@"$line" 'show inventory' | grep PID | awk '{print $2,$7,$8}' | sed 's/ //g' | grep -v "," | sort | uniq | sed 's/SN:/,Serial:/g' |\
            grep -v "SFP\|FANTRAY\|FTRJ\|GLC\|FTLF\|STACK" >> "$results"
    
            printf "\n" >> "$results"
    done
        # Send results to an email 
        echo "Export generated: $(date). See attachment." | mailx -r "$sender" -S "$mailrelay" -s "$mailsubject" -a "$results" -v "$mailto"
        echo
        # Send done message to console
        echo "Done, check "$results"! or email"
        echo
    

    Firefly III has a recurring transactions option. In order for that to work, you need to setup a cronjob. Without that, you get an error at the top of the page saying:

    It seems the cron job that is necessary to support recurring transactions has never 
    run. This is of course normal when you have just installed Firefly III, 
    but this should be something to set up as soon as possible. Please check 
    out the help-pages using the (?)-icon in the top right corner of the page.

    Firefly III has an API to which you make a get request that triggers recurring transactions update. API call URL is:

    http://FIREFLY_URL/api/v1/cron/TOKEN

    To generate a token, go to your Firefly GUI -> Options -> Profile -> Command line token and copy token to URL.

    Example:

    http://firefly.example/api/v1/cron/6c57c098904f6f4765b52a4bc493687p

    If you go to this URL now, your Firefly will run recurring transactions. Because we don’t want to do that manually, we will do it via cronjob that will run every day at 3 AM.

    You can do it on any Linux box with normal cronjob:

    crontab -e

    and add this line:

    0 3 * * * wget -qO- http://firefly.example/api/v1/cron/6c57c098904f6f4765b52a4bc493687p &> /dev/null

    Because we are running Firefly 3 in Docker, more neat option is to add Alpine linux image to our docker compose and run it along within stack:

    version: '3.3'
    
    services:
      app:
        image: fireflyiii/core:latest
        restart: always
        volumes:
          - firefly_iii_upload:/var/www/html/storage/upload
        env_file: stack.env
        ports:
          - 8080:8080
        depends_on:
          - db
      db:
        image: mariadb:10.8.2
        hostname: fireflyiiidb
        restart: always
        environment:
          - MYSQL_RANDOM_ROOT_PASSWORD=yes
          - MYSQL_USER=firefly
          - MYSQL_PASSWORD=secret_firefly_password
          - MYSQL_DATABASE=firefly
        volumes:
          - firefly_iii_db:/var/lib/mysql
      cron:
         image: alpine
         command: sh -c "echo \"0 3 * * * wget -qO- http://firefly.example/api/v1/cron/6c57c098904f6f4765b52a4bc493687p &> /dev/null\" | crontab - && crond -f -L /dev/stdout"
    volumes:
       firefly_iii_upload:
       firefly_iii_db:

    After the stack is running, enter a shell of your Alpine container and check if cronjob is present:

    crontab -l

    There is a Python tool called pyang that can read yang files. To install it on Linux machine:

    apt install git python3-pip
    pip install pyang

    Now, git clone yang data model to your linux machine:

    cd ~;git clone https://github.com/YangModels/yang.git

    Pyang by itself is capable of reading yang and present it as a tree. To get xpath, we need to install additional plugin from here: https://github.com/NSO-developer/pyang-xpath
    Find your pyang installation, and put the the xpath plugin to the plugin folder:

    find /usr/local/lib -iname pyang
    /usr/local/lib/python3.10/dist-packages/pyang

    Download plugin:

    wget -O /usr/local/lib/python3.10/dist-packages/pyang/plugins/xpath.py https://raw.githubusercontent.com/NSO-developer/pyang-xpath/master/xpath.py

    Go to Yang model you cloned a few steps back (in this example, we’ll find xpath for Cisco IOS-XE cpu usage:

    cd ~/yang/vendor/cisco/xe/1781/

    Use xpath module on yang file to get xpath:

    pyang -f xpath Cisco-IOS-XE-process-cpu-oper.yang 
    >>> module: Cisco-IOS-XE-process-cpu-oper
    /cpu-usage
    /cpu-usage/cpu-utilization
    /cpu-usage/cpu-utilization/five-seconds
    /cpu-usage/cpu-utilization/five-seconds-intr
    /cpu-usage/cpu-utilization/one-minute
    /cpu-usage/cpu-utilization/five-minutes
    /cpu-usage/cpu-utilization/cpu-usage-processes
    /cpu-usage/cpu-utilization/cpu-usage-processes/cpu-usage-process
    /cpu-usage/cpu-utilization/cpu-usage-processes/cpu-usage-process/pid
    /cpu-usage/cpu-utilization/cpu-usage-processes/cpu-usage-process/name
    /cpu-usage/cpu-utilization/cpu-usage-processes/cpu-usage-process/tty
    /cpu-usage/cpu-utilization/cpu-usage-processes/cpu-usage-process/total-run-time
    /cpu-usage/cpu-utilization/cpu-usage-processes/cpu-usage-process/invocation-count
    /cpu-usage/cpu-utilization/cpu-usage-processes/cpu-usage-process/avg-run-time
    /cpu-usage/cpu-utilization/cpu-usage-processes/cpu-usage-process/five-seconds
    /cpu-usage/cpu-utilization/cpu-usage-processes/cpu-usage-process/one-minute
    /cpu-usage/cpu-utilization/cpu-usage-processes/cpu-usage-process/five-minutes
    

    This are all xpaths, but we still need a prefix to construct a full path. It’s written at the start of the file:

    grep prefix Cisco-IOS-XE-process-cpu-oper.yang
      prefix process-cpu-ios-xe-oper;

    The whole xpath (level 1 depth) would look like this:

    process-cpu-ios-xe-oper:cpu-usage/cpu-utilization

    Depends on the depth and data needed, you can use this xpath with Cisco IOS-XE switch. Example:

    telemetry ietf subscription 3305
     encoding encode-kvgpb
     filter xpath /process-cpu-ios-xe-oper:cpu-usage/cpu-utilization
     source-address 10.10.1.1
     stream yang-push
     update-policy periodic 3000
     receiver ip address 10.20.20.250 57000 protocol grpc-tcp
    

    References:
    https://community.cisco.com/t5/service-providers-knowledge-base/how-to-derive-exr-telemetry-yang-path-using-pyang/ta-p/3713864
    https://github.com/NSO-developer/pyang-xpath
    https://github.com/jeremycohoe/cisco-ios-xe-mdt
    https://www.youtube.com/watch?v=p94yetSTXdc
    https://github.com/YangModels/yang

    Looks like the latest MariaDB is not playing nice with Docker. It keeps on restarting, that’s why Firefly app can’t access it. This are the errors:

    firefly_app-1 error:

    getaddrinfo for db failed: Temporary failure in name resolution
    

    firefly_db-1 error:

    [Note] [Entrypoint]: Entrypoint script for MariaDB Server 1:10.9.2+maria~ubu2204 started.
    [ERROR] [Entrypoint]: mariadbd failed while attempting to check config
            command was: mariadbd --verbose --help --log-bin-index=/tmp/tmp.UIQ7MFsJkX
            Can't initialize timers
    

    Fix: use older version of Mariadb, in my example, 10.8.2

    My docker-compose file:

    version: '3.3'
    
    services:
      app:
        image: fireflyiii/core:latest
        restart: always
        volumes:
          - firefly_iii_upload:/var/www/html/storage/upload
        env_file: stack.env
        ports:
          - 8080:8080
        depends_on:
          - db
      db:
        image: mariadb:10.8.2
        hostname: fireflyiiidb
        restart: always
        environment:
          - MYSQL_RANDOM_ROOT_PASSWORD=yes
          - MYSQL_USER=firefly
          - MYSQL_PASSWORD=secret_firefly_password
          - MYSQL_DATABASE=firefly
        volumes:
          - firefly_iii_db:/var/lib/mysql
    volumes:
       firefly_iii_upload:
       firefly_iii_db:
    

    My notes on converting Cisco Catalyst 9105, 9115, 9xxx series access points to autonomous AP with embedded wireless controller.

    Connect to your AP with console cable.

    User: Cisco
    Pass: Cisco
    Enable: Cisco
    

    Setup connectivity betweeen TFTP (in my case running on windows PC – tftpd64) server and AP.

    TFTP server IP: 192.168.1.1/24
    AP IP: 192.168.1.2/24

    capwap ap ip 192.168.1.2 255.255.255.0 192.168.1.1
    

    #version <= 8.9:

    ap-type mobility-express ap-type ewc-ap tftp://192.168.1.1/ap1g7 tftp://192.168.1.1/C9800-AP-iosxe-wlc.bin
    

    #version > 8.9:

    ap-type ewc-ap tftp://192.168.1.1/ap1g7 tftp://192.168.1.1/C9800-AP-iosxe-wlc.bin
    

    The conversion begins …

    Would you like to enter the initial configuration dialog? [yes/no]: enter no
    
     The enable secret is a password used to protect
      access to privileged EXEC and configuration modes.
      This password, after entered, becomes encrypted in
      the configuration.
      -------------------------------------------------
      secret should be of minimum 10 characters with
      at least 1 upper case, 1 lower case, 1 digit and
      should not contain [cisco]
      -------------------------------------------------
      Enter enable secret: 
    
    [0] Go to the IOS command prompt without saving this config.
    [1] Return back to the setup without saving this config.
    [2] Save this configuration to nvram and exit.
    

    Select 0

    conf t
    hostname C9800
    

    Create admin user – also used for web GUI:

    user-name admin
    priv 15
    password test123
    

    Set ap profile:

    ap profile ap-default
    

    Configure management user for access points:

    mgmtuser username admin password 0 test123 secret 0 test123
    

    Configure management IP address (you will access it via SSH or web GUI):

    interface gigabitEthernet 0
    ip address 192.168.1.2 255.255.255.0
    no shut
    ip default-gateway 192.168.1.1
    

    Enable web server and save config:

    ip http secure-server
    wr
    

    Access EWLC via https://192.168.1.2

    All commands together after conversion is done:

    WLCA49B.FFFF.BEEF#configure terminal
    WLCA49B.FFFF.BEEF(config)#hostname C9800
    C9800(config)#user-name admin
    C9800(config-user-name)#priv 15
    C9800(config-user-name)#password test123
    C9800(config-user-name)#ap profile ap-default
    C9800(config-ap-profile)#$mgmtuser username admin password 0 test123 secret 0 test123
    C9800(config-ap-profile)#interface gigabitEthernet 0
    C9800(config-if)#ip address 192.168.1.2 255.255.255.0
    C9800(config-if)#no shut
    C9800(config-if)#ip default-gateway 192.168.1.1
    C9800(config)#ip http secure-server
    C9800(config)#do wr
    Building configuration...
    [OK]
    C9800(config)#
    

    reference: https://www.youtube.com/watch?v=NBt370eiQ3I

    There seems to be some bug in the newest Cisco 5G cellular gateway (CG522-E), shipped with 17.05 firmware. When you insert a SIM card, Linux cwand subsystem crashes and it keeps cycling, not detecting the SIM card:

    Subsystem stopped: cwand
    CellularGateway# pid 4342's current affinity list: 0-3
    pid 4342's new affinity list: 0
    pid 4344's current affinity list: 0-3
    pid 4344's new affinity list: 0
    pid 4345's current affinity list: 0-3
    pid 4345's new affinity list: 0
    pid 4346's current affinity list: 0-3
    pid 4346's new affinity list: 0
    pid 4348's current affinity list: 0-3
    pid 4348's new affinity list: 0
    pid 4349's current affinity list: 0-3
    pid 4349's new affinity list: 0
    
    System message at 2022-07-28 07:35:27...
    Subsystem started: cwand

    Guessing this has something to do with congestion windows parameter settings in the Linux subsystem, in combination with our SIM card (mobile network) specifications.

    The only solution was to downgrade to 17.04 firmware. That fixed the issue for now.

    Note: scroll to bottom of the post for the final solution.

    When you try to login to TPlink switch from pfSense console you get the following error:

    ssh admin@10.10.10.1
    Unable to negotiate with 10.10.10.1 port 22: no matching key exchange method found. Their offer: diffie-hellman-group1-sha1
    

    Next you try to enable diffie-hellman group, another error pops up:

    ssh -oKexAlgorithms=+diffie-hellman-group1-sha1 admin@10.10.10.1
    Unable to negotiate with 10.10.10.1 port 22: no matching host key type found. Their offer: ssh-dss
    

    Now you also include ssh-dss, but you still get an error:

    ssh -oKexAlgorithms=+diffie-hellman-group1-sha1 -oHostKeyAlgorithms=+ssh-dss admin@10.10.10.1
    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    @    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
    Someone could be eavesdropping on you right now (man-in-the-middle attack)!
    It is also possible that a host key has just been changed.
    The fingerprint for the DSA key sent by the remote host is
    SHA256:h1gD8T017XJ19NjY3wD9Vob81jHYUJubf2M23KLU7OU.
    Please contact your system administrator.
    Add correct host key in /root/.ssh/known_hosts to get rid of this message.
    Offending RSA key in /root/.ssh/known_hosts:1
    DSA host key for 10.10.10.1 has changed and you have requested strict checking.
    Host key verification failed.
    

    Now you disable strict host checking and you get the following error:

    ssh -oKexAlgorithms=+diffie-hellman-group1-sha1 -oHostKeyAlgorithms=+ssh-dss -o StrictHostKeyChecking=no admin@10.10.10.1
    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    @    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
    Someone could be eavesdropping on you right now (man-in-the-middle attack)!
    It is also possible that a host key has just been changed.
    The fingerprint for the DSA key sent by the remote host is
    SHA256:h1gD8T017XJ19NjY3wD9Vob81jHYUJubf2M23KLU7OU.
    Please contact your system administrator.
    Add correct host key in /root/.ssh/known_hosts to get rid of this message.
    Offending RSA key in /root/.ssh/known_hosts:1
    Password authentication is disabled to avoid man-in-the-middle attacks.
    Keyboard-interactive authentication is disabled to avoid man-in-the-middle attacks.
    Permission denied (publickey,password).
    

    The final working solution, enable diffie and ssh-dss, disable strict host checking and redirect known hosts file to /dev/null:

    ssh -oKexAlgorithms=+diffie-hellman-group1-sha1 -oHostKeyAlgorithms=+ssh-dss -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o PasswordAuthentication=yes admin@10.10.10.1
    

    When deploying paperless-ng stack with docker-compose file in Portainer you can’t login to paperless admin because superuser for login is missing (not created). You need to create it by going into container webserver CLI console and create it. Check screenshots for details.

    python3 manage.py createsuperuser
    

    For reference, this is my docker-compose.yml file with some additional services (Tika and Gotenberg – used for parsing and converting Office documents):

    version: "3.4"
    services:
      broker:
        image: redis:6.0
        restart: unless-stopped
    
      db:
        image: postgres:13
        restart: unless-stopped
        volumes:
          - pgdata:/var/lib/postgresql/data
        environment:
          POSTGRES_DB: paperless
          POSTGRES_USER: paperless
          POSTGRES_PASSWORD: paperless
    
      webserver:
        image: jonaswinkler/paperless-ng:latest
        restart: unless-stopped
        depends_on:
          - db
          - broker
          - gotenberg
          - tika
        ports:
          - 8010:8000
        healthcheck:
          test: ["CMD", "curl", "-f", "http://localhost:8000"]
          interval: 30s
          timeout: 10s
          retries: 5
        volumes:
          - data:/usr/src/paperless/data
          - media:/usr/src/paperless/media
          - ./export:/usr/src/paperless/export
          - ./consume:/usr/src/paperless/consume
        environment:
          PAPERLESS_REDIS: redis://broker:6379
          PAPERLESS_DBHOST: db
          PAPERLESS_TIKA_ENABLED: 1
          PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000
          PAPERLESS_TIKA_ENDPOINT: http://tika:9998
          PAPERLESS_TIME_ZONE: Europe/Ljubljana
          PAPERLESS_OCR_LANGUAGES: slv
          # consumption directory.
          USERMAP_UID: 1000
          USERMAP_GID: 100
    
      gotenberg:
        image: thecodingmachine/gotenberg
        restart: unless-stopped
        environment:
          DISABLE_GOOGLE_CHROME: 1
    
      tika:
        image: apache/tika
        restart: unless-stopped
    
    volumes:
      data:
      media:
      pgdata:
    

    This is for Windows 10. You need supported bluetooth dongle, refer to cisco documentation. In my tests, I used ASUS BT-400 USB dongle.

    Pair your switch to your Windows computer. Default pairing PIN is 9999. Now follow the screenshot bellow:

    After the connection is completed, you can SSH to the device via default IP 172.16.0.1.

    Bluetooth commands references – in enable mode:

    staging config bluetooth on (this will turn on the bluetooth - it's on by default)
    staging config bluetooth PIN OLD_PIN NEW_PIN (change default pairing PIN)
    

    Default bluetooth interface is Bluetooth0

    For Cisco C9000 series, you need different configuration as described here: https://www.cisco.com/c/en/us/td/docs/switches/lan/catalyst9500/software/release/16-12/configuration_guide/int_hw/b_1612_int_and_hw_9500_cg/configuring_an_external_usb_bluetooth_dongle.pdf

    Docker by default uses networks from 172.17.0.0/16 private range. This can sometimes conflicts with network you already have in your network environment. This will cause routing problems when clients from the same network subnets will try to access Docker services. In this case, Docker will route packets to containers instead back to clients.

    To solve this, you need to define unused subnets and assign it to Docker. You can do this with daemon.json file.

    Edit file (it if doesn’t exist, create it):

    nano /etc/docker/daemon.json

    Add this and edit to your needs:

    {
      "bip": "172.17.192.1/26",
      "default-address-pools": [
        {
          "base": "172.17.192.64/28",
          "size": 29
        }
      ]
    }
    

    “bip”: “172.17.192.1/26” – This will be used for docker0 interface
    “base”: “172.17.192.64/28” – This will be used for container bridges
    “size”: 29 – Subnet prefix, means how large is going to be each bridge

    Save file and restart docker:

    service docker restart

    In case you used docker-compose, first delete networks and containers with:

    docker-compose down

    In case you have more old bridges, list them with:

    docker network ls

    and delete with:

    docker network rm network_name

    or delete all networks with:

    docker network prune

    Alternatively, use a portion ob public network that you’re never going to use, for example:

    {
      "bip": "100.100.100.1/26",
      "default-address-pools": [
        {
          "base": "100.100.100.64/28",
          "size": 29
        }
      ]
    }
    

    Or use host networking, this will bind container network directly to host. But you will lose container isolation with this method: https://docs.docker.com/network/host/

    New unboxed Cisco ISR4331, command configure terminal didn’t work. Looks like the router is booted in controller mode by default. To get back to “legacy” mode you need to disable controller mode.

    Router#conf t
    This command is not supported
    
    Router# controller-mode disable
    Disabling controller mode will erase the nvram filesystem, remove all configuration files, and reload the box!
    Ensure the BOOT variable points to a valid image
    Continue? [confirm]
    % Warning: Bootstrap config file needed for Day-0 boot is missing
    Do you want to abort? (yes/[no]): no
     Mode change success
    

    Wait a few minutes, router will reload.

    Router>en
    Router#conf t
    Enter configuration commands, one per line.  End with CNTL/Z.
    Router(config)#
    

    I added an extra network card to my Proxmox server (Mellanox Connect-X3) and some VLANs were not working. It turned out Mellanox Connect-X3 supports only about 128 VLANS in memory. Proxmox by default adds VLANs from 2-4094. You can see it in /etc/network/interfaces, line bridge-vids 2-4094.

    When you try to reload networking from console, you get this error:

    root@proxmox:~# ifreload -a
    error: enp1s0: failed to set vid `{2,...4094}` (cmd '/sbin/bridge vlan add vid 2-4094 dev enp1s0' 
    failed: returned 255 (RTNETLINK answers: No space left on device))
    

    To fix this, open /etc/network/interfaces and add only VLANs you need. For example:

    Original:

    auto vmbr1
    iface vmbr1 inet manual
            bridge-ports enp1s0
            bridge-stp off
            bridge-fd 0
            bridge-vlan-aware yes
            bridge-vids 2-4094
    

    Fixed:

    auto vmbr1
    iface vmbr1 inet manual
            bridge-ports enp1s0
            bridge-stp off
            bridge-fd 0
            bridge-vlan-aware yes
            bridge-vids 20,21,30,40,50,60,90,200,210,254,600,664-668
    

    Restart networking:

    ifreload -a
    

    Assign VLANs to your VMs now, it should work.

    Prerequisites:

    – raspbian OS
    – CA cert, client cert and cert password, client key

    You can use .p12 file and convert it to .pem, it will include client cert and client key in the same file. Let’s say you download .p12 file from PfSense cert manager. Convert it with:

    openssl pkcs12 -in test.p12 -out test.pem
    Enter Import Password: leave empty
    Enter PEM pass phrase: testing1234
    Verifying - Enter PEM pass phrase: testing1234
    

    First, delete openresolv and dhcpcd5 because it’s conflicting with native network management:

    apt purge openresolv dhcpcd5

    Disable wpa_supplicant:

    systemctl disable wpa_supplicant

    Install nmcli:

    apt install network-manager

    Comment out everything in /etc/network/interfaces and in /etc/wpa_supplicant/wpa_supplicant.conf and then Reboot Pi

    Create wifi connection:

    nmcli c add type wifi ifname wlan0 con-name "My-Wifi" \
          802-11-wireless.ssid "WIFI-SSID" \
          802-11-wireless-security.key-mgmt wpa-eap \
          802-1x.eap tls \
          802-1x.identity test \
          802-1x.ca-cert /home/pi/CA.crt \
          802-1x.client-cert /home/pi/test.pem \
          802-1x.private-key /home/pi/test.pem \
          802-1x.private-key-password testing1234
    

    Depending on the network-manager version, the commands above might not work, so just enter it manually line by line:

    nmcli con add type wifi ifname wlan0 con-name My-Wifi ssid WIFI-SSID
    nmcli con edit id wifi
    nmcli> set 802-11-wireless.ssid WIFI-SSID
    nmcli> set 802-11-wireless-security.key-mgmt wpa-eap
    nmcli> set 802-1x.eap tls
    nmcli> set 802-1x.identity test
    nmcli> set 802-1x.ca-cert /home/pi/CA.crt
    nmcli> set 802-1x.client-cert /home/pi/test.pem
    nmcli> set 802-1x.private-key-password testing1234
    nmcli> set 802-1x.private-key /home/pi/test.pem
    nmcli> save
    nmcli> quit
    

    Check connection with:

    nmcli connection
    NAME                UUID                                  TYPE      DEVICE
    My-Wifi             f0c28a28-934f-4dbc-823f-b3c1653bb047  wifi      wlan0
    

    Start connection:

    nmcli connection up My-Wifi
    

    If you want to start over, you can delete connection with:

    nmcli connection delete My-Wifi
    

    You can also view and edit profile at /etc/NetworkManager/system-connections/My-Wifi.nmconnection

    cat /etc/NetworkManager/system-connections/My-Wifi.nmconnection
    [connection]
    id=My-Wifi
    uuid=f0c28a28-934f-4dbc-823f-b3c1653bb047
    type=wifi
    interface-name=wlan0
    permissions=
    
    [wifi]
    mac-address-blacklist=
    mode=infrastructure
    ssid=WIFI-SSID
    
    [wifi-security]
    key-mgmt=wpa-eap
    
    [802-1x]
    ca-cert=/home/pi/CA.crt
    client-cert=/home/pi/test.pem
    eap=tls;
    identity=test
    private-key=/home/pi/test.pem
    private-key-password=testing1234
    
    [ipv4]
    dns-search=
    method=auto
    
    [ipv6]
    addr-gen-mode=stable-privacy
    dns-search=
    method=auto
    

    We are going to install Cisco wireless virtual controller on Proxmox hypervisor and connect it to pfSense router.

    Prerequisites:

    • pfSense router with required VLANS created and tagged to Proxmox (I will not cover how to setup VLANs on pfSense)
    • VLAN capable switch
    • Cisco access point
    • Proxmox hypervisor
    • vWLC iso file (you can get it from Cisco support site if you have a service contract, otherwise search the internet, hint: torrents (CTVM)). Check your access points models and see which vWLC supports your access points. In my case, I want to support some older APs so I installed version 8.3.150. I recommend you to install 8.5.x.

    1. Create a new virtual machine in Proxmox
    vWLC requires two network interfaces, one for management and one for out of band (OOB) service port. Management interface has to be a trunk (tagged) port (carrying multiple vlans). Service port has to be an access port only (untagged). Let’s say we will use VLAN 20 for management, VLAN 200 for service ports and VLAN 21 for wifi users. Before creating interfaces in vWLC virtual machine, make sure your Proxmox bridges are VLAN aware.

    2. Create a new VM and add two interfaces.
    First interface should be tagged with service-port VLAN, in  my case VLAN 200. The second interface should have no tag, that means it’s a trunk port (it can carry multiple VLANS).

    3. Start up newly created VM with loaded vWLC ISO and begin installation
    You will be asked to enter:

    – service port interface IP (you can use DHCP or static, this is a tagged/access port interface, with VLAN 200 in my case)
    – management interface IP (this is a trunk interface, but it will ask you for a vlan tag that will become native vlan for this interface … Tag it, in my case VLAN 20, it needs to be static IP address, set it to IP address scheme that reflects your VLAN, in my case VLAN 20)
    – NTP server
    – credentials

    After installation is complete, you should be able to access vWLC webGUI via https://management_interface_IP_on_VLAN20

    4. Access point provisioning, DHCP option 43
    It will happen on management interface vlan, in my case VLAN 20. APs will need to know the IP of the vWLC controller, so we need to setup option 43 in our DHCP server that’s running on pfSense. Option 43 will tell access point the IP of the vWLC controller. You can help yourself with an option 43 generator (https://shimi.net/services/opt43/). More detailed guide from Cisco concerning option 43 is here: https://community.cisco.com/t5/wireless-mobility-documents/configuring-dhcp-option-43-and-option-60/ta-p/3143572


    Optionally, you can also add option 60 (VCI – Vendor Class Identifier). You can get APs VCIs here: https://www.cisco.com/c/en/us/support/docs/wireless-mobility/wireless-lan-wlan/97066-dhcp-option-43-00.html#anc5

    Go to pfSense -> Services -> DHCP Server -> VLAN20 -> Additional BOOTP/DHCP Options -> Display Advanced


    Save and apply changes.

    EDIT: option 43 should be type string, not text!

    5. Switch settings
    vWLC supports only Flexconnect mode, that means you need to setup your switch ports (where APs will be connected to it) as a trunk port and setup a native VLAN. For non Cisco terms: untagged + tagged ports. Native VLAN should be the same as management interface, in my case VLAN 20. Trunk should also carry VLAN 21 for wifi clients.

    Example for cisco:

    interface GigabitEthernet1/0/1
    switchport trunk native vlan 20
    switchport trunk allowed vlan 20,21
    switchport mode trunk

    Other vendors have tagging and untagging, so VLAN 20 untagged, VLAN 21 tagged.

    6. Connect AP to configured switch port
    Connect AP to the switch and wait a few minutes to join the controller. If AP doesn’t join, check logs on WLC controller: MANAGEMENT -> Logs -> Message logs

    If you get: (5246) Regulatory Domain Mismatch

    Means you have to change country code to match the AP (usually US):

    Shutdown radios first:

    WLC GUI -> Wireless -> 802.11a/n/ac -> Network -> 802.11a Network Status (untick Enabled and apply)
    WLC GUI -> Wireless -> 802.11b/g/n -> Network -> 802.11a Network Status (untick Enabled and apply)

    Change country:

    WLC GUI -> WIRELESS -> Country -> Tick US and apply

    Reenable radios now.

    Sometimes AP still won’t join, especially old ones. If you connect AP to a console cable and watch a console, you might get someting like:

    *Oct 7 18:44:58.000: %CAPWAP-5-DTLSREQSEND: DTLS connection request sent peer_ip: 192.168.20.16 peer_port: 5246
    *Oct 7 18:44:58.477: %DTLS-5-ALERT: Received FATAL : Certificate unknown alert from 192.168.20.16
    *Oct 7 18:44:58.477: %DTLS-5-SEND_ALERT: Send FATAL : Close notify Alert to 192.168.20.16:5246

    This means the certs on AP are expired. You can disable this by SSH into vWLC controller and enter the following commands:

    config ap cert-expiry-ignore mic enable
    config ap cert-expiry-ignore ssc enable

    7. Enable SSID broadcasting
    vWLC supports only Flexconnect, so we need to enable it:

    Go to WLC GUI -> WIRELESS -> Access Points -> All APs -> select AP from the list -> AP Mode -> FlexConnect and apply

    8. Create wireless network
    First you need to create VLAN interface for wifi clients.

    Go to WLC GUI -> Controller -> Interfaces -> New -> Interface name: vlan21 -> VLAN Id: 21 -> Apply

    Now create WLAN network

    Go to WLC GUI -> WLANs -> Create new -> Enter Profile Name and SSID -> tick Status enabled and select Interface/Interface Group(G) vlan21 -> go to Security -> Layer 2 -> scroll down -> tick PSK Enable and create a wifi password -> Apply

    9. Enable VLANs on AP
    You need to setup native VLAN (in my case VLAN 20) on APs and add WLAN-VLAN mappings.

    Go to WLC GUI -> WIRELESS -> Access Points -> All APs -> select AP from the list -> FlexConnect, tick VLAN support and enter native VLAN:

    Next click on VLAN Mappings. Tick SSID under WLAN id, enter wifi clients VLAN under VLAN ID (in my case VLAN 21) and click Go at section Make AP specific.

    10. You wifi clients should be able to connect now

    11. 60 days trial license

    There is a 60 days trial license, but you can enable RTU (right to use) license that will not expire (note: this is against cisco TOS).

    Go to WLC GUI -> MANAGEMENT -> Software Activation -> Licenses -> license count: custom number -> Set Count -> Accept EULA and you are done.

    12. Quick topology drawing