Tag: fortiswitch

  • Quick tips: FortiSwitch custom command double quotes, ZTNA SAML vhost error, session evaluation after ZTNA tag changes

    Not every post needs to be something that takes hours to get together, and that is why I want to start a new type of post, where I write about things I experience in my day-to-day, that seem interesting, and want to put out there, so maybe someone else doesn’t have to spend hours looking for a solution.

    With that, dear reader, read about the quick tips for today.

    Models and versions:

    • FortiGate 70G on 7.6.6
    • FortiSwitch 424E on 7.6.6
    • FortiClient EMS on 7.4.7
    • FortiClient on 7.4.6
    • Windows 11 client on 25H2

    Handling double quotes in FortiSwitch custom commands

    Custom commands are an important part of managing FortiSwitches, because not every piece of configuration you can make on a FortiSwitch is available on the FortiGate. Lots of things you don’t touch every day have to be configured using custom commands, and in some cases, you run into the issue of having to use double quotes, which creates an issue, because double quotes, on the FortiGate, signify where the custom command starts and where it ends.

    Looking at the example that prompted this post: You want to push a Certificate Authority (CA) certificate to a FortiSwitch for LDAPS authentication.

    On a FortiSwitch, this would look like this (certificate shortened for brevity):

    config system certificate ca
        edit WIN-CA
    	set ca "-----BEGIN CERTIFICATE-----
    		MIIFrDCCA5SgAwIBAgIQP+FZ4Onx66RLEDsn8YuCGTANBgkqhkiG9w0BAQ0FADBV
    		MRMwEQYKCZImiZPyLGQBGRYDY29tMRkwFwYKCZImiZPyLGQBGRYJbGFiZG9tYWlu
    		MRIwEAYKCZImiZPyLGQBGRYCYWQxDzANBgNVBAMTBldJTi1DQTAeFw0yNTA4MDIx
    		...
    		TETr69CP4eDwJGD7gZp8Lnz98Xj+fQUcco+/9xuK7JXQlE97H05Mn32YZmv4aFC0
    		v2S0t0Lk+YqUVZKAMRfnZ9nu8dTHFE4Q+5TqOxcyEwpmAeXRIWs/HPOXhegu87tu
    		bqYj4gD9n/S8BjlOqtx/Yw==
    		-----END CERTIFICATE-----"
        next
    end

    The double quotes in the BEGIN CERTIFICATE line will create your first problem when using a custom command. If you want to push this certificate using a custom command on the FortiGate, you have to replace the double quotes with a % symbol followed by the hex code. In this case, it would be %22.

    Using it in a custom command, we can deploy a CA certificate like this (certificate shortened for brevity):

    config switch-controller custom-command
        edit "WIN-CA"
            set command "config system certificate ca%0a edit WIN-CA%0a set ca %22-----BEGIN CERTIFICATE-----%0aMIIFrDCCA5SgAwIBAgIn/S8BjlOqtx/Yw==%0a-----END CERTIFICATE-----%22%0a next%0a end%0a"
        next
    end
    config switch-controller managed-switch
        edit "SERIAL/NAME"
            config custom-command
                edit "WIN-CA"
                    set command-name "WIN-CA"
                next
            end
        next
    end

    Someone hinted at the possibility of this by telling me to use a backslash and the hex code, which didn’t work, and then I remembered that in custom commands, %0a should be used for a line feed, and 0a is the hex code for that. Put two and two together, and you end up with %22.

    Thank you to this specific person, who, I am sure, wants to remain anonymous, but he will likely read this.

    If you ever need a lookup table or a converter for characters and their hex representation, check out one of the many sites that offer this, like this one: ASCII Character Chart with Decimal, Binary and Hexadecimal Conversions

    ZTNA “failed to match an API-gateway” error using SAML SSO authentication

    If you’re configuring SAML SSO authentication for your ZTNA connections and you run into the issue where FortiClient displays a “The page you requested has been blocked because no API gateway was matched” and the FortiGate shows an error like “Traffic denied because HTTP url (https://ztnaproxy.domain.com/tcp?address=win-ad.ad.labdomain.com&port=3389&tls=0) failed to match an API-gateway with vhost(name/hostname:saml_auto_vhost_SAML/ztnaproxy.domain.com)” (the FQDN and the “SAML” is custom and will look different for you), I might have an answer for you.

    Go into your ZTNA server configuration and the service/server mapping, specify the virtual host, supply a host matched by a substring that corresponds to the domain from the HTTPS URL in the error, and select your certificate.

    ZTNA virtual host
    config firewall access-proxy-virtual-host
        edit "auto-ztna-vhmoifbct0"
            set ssl-certificate "ztnaproxy.domain.com"
            set host "ztnaproxy.domain.com"
        next
    end
    config firewall access-proxy
        edit "LAB-ZTNA"
            set vip "LAB-ZTNA"
            config api-gateway
                edit 1
                    set url-map "/tcp"
                    set service tcp-forwarding
                    set virtual-host "auto-ztna-vhmoifbct0"
                    config realservers
                        edit 1
                            set address "win-ad.ad.labdomain.com"
                            set mappedport 3389
                        next
                        edit 2
                            set address "ubuntu-ws-1.ad.labdomain.com"
                            set mappedport 80
                        next
                    end
                next
                edit 2
                    set service samlsp
                    set saml-server "ENTRA-SAML"
                next
            end
        next
    end

    I’m not sure why this error happened, because I have configured this thing before without having to specify a virtual host, but this works.

    [Update 2026-04-29]: Yesterday, in bed, I found the cause of this behaviour change. Since 7.6.1 FortiOS learns, and creates, a virtual host implicitly from a SAML authentication when using ZTNA. The proposed workaround of “To avoid this behavior, put the SAML api-gateway in a separate access-proxy and use a different virtual host for your server.” is a bit confusing to me, but unless you have multiple SAML servers for ZTNA, which creates other issues due to authentication rules, it’s not relevant. If you have multiple SAML servers, you will always fall into the authentication rule that is first in the list, unless you configure source and/or destination addresses (CLI-only), so you can authenticate with that one, and you get a user on the FortiGate in WAD, but authorization will fail, because you are hitting a proxy rule with one SAML server, but you were authenticated with another.

    Evaluating firewall sessions after dynamic address changes (ZTNA tags, FSSO)

    After solving the error from the previous section, I played around with ZTNA tags and noticed that, if a tag changes, existing sessions won’t get evaluated and possibly blocked. This is something you have to be aware of. If you are using dynamic address objects, you probably want existing sessions to not transfer traffic if new ones should get blocked.

    Think of an attacker establishing a channel from inside your network to an external command and control server, and if your ZTNA tags notice this, this connection won’t get blocked, because it’s an existing session.

    If you want existing firewall policies to get evaluated if dynamic address objects change, be that ZTNA tags, FQDN objects, Fortinet Single Sign-On (FSSO) objects, or otherwise, it’s only a single command away.

    config system settings
        set dyn-addr-session-check enable
    end

    Short and sweet and done

    I might do this type of post more often, and I hope that you, dear reader, can take something away from this.

  • FortiLink over layer 2 with a third-party switch

    Want to learn more about how to make FortiLink work over layer 2 with a third-party switch in the mix? Yes? Then let’s go!

    Disclaimer

    I want to stress that this type of configuration shouldn’t be your go-to. It’s something you do because you need it. Doing it “right” involves only FortiSwitches.

    I have also experienced some issues with FortiSwitch’s DHCP client process during the quick version, where the DHCP traffic was sometimes blocked somewhere, but layer 2 data traffic worked. Changing the FortiSwitch’s internal interface to static and back to DHCP solved this issue. A port bounce also worked, but it is more disruptive. Not sure if this is a firmware issue on FortiSwitch or a problem with my third-party switch.

    [Update 2026-05-02]: Since this post was written, Fortinet has created a technical tip article that focuses on this topic as well, except they use FortiSwitch management using HTTPS, which was introduced in 7.4.2. Check out this method, and maybe it works better for you: Technical Tip: Configuring FortiLink over 3rd party switches with L2 connectivity with the FortiGate

    The setup

    For this article, I have:

    • A FortiGate 60F on 7.6.5
    • 2x FortiSwitch 424E on 7.6.6
    • A FortiSwitch 108F on 7.6.6
    • An HPE Aruba CX 6000
    • An HPE Aruba 2530

    This should work with any enterprise third-party switch, because we only need VLANs, STP, and LACP.

    Layer 2 topology

    In this article, I will focus on making this all work using the virtual internal interface, not the dedicated physical mgmt interface that some FortiSwitch models have (mainly because the physical interface makes this entire thing a non-issue).

    The internal interface is a virtual in-band interface that is used for management purposes. You can use it for administrative access (SSH, HTTPS, etc.), and it’s also used to source the traffic that is relevant for FortiLink to function.

    The quick version 

    If you just want to get this configuration working and you don’t intend on connecting an additional FortiSwitch to the one you configure, or you’re fine with doing some manual configuration later to do so, this section is for you. If you want to know more about how all of this works, the pitfalls, and scalability, you can skip the quick version sections.

    The quick version: Third-party switch

    On the third-party switch, you have two links, which for me are both LACP LAGs, but they can also be non-LACP and non-LAG links. These links should be 802.1Q trunks where the native VLAN on both links can be one you pick, unless it’s 4094. The detailed explanation further down expands on why not this one. The allowed VLANs should match on both links. This is everything we need on the third-party switch.

    Third-party switch config (quick)

    vlan 4084
        name NATIVE
    interface lag 1
        description FORTIGATE-LAG
        no shutdown
        vlan trunk native 4084
        vlan trunk allowed all
        lacp mode active
    interface lag 2
        description FORTISWITCH-LAG
        no shutdown
        vlan trunk native 4084
        vlan trunk allowed all
        lacp mode active
    interface 1/1/1
        description FORTIGATE-LAG-MEMBER
        no shutdown
        lag 1
    interface 1/1/2
        description FORTISWITCH-LAG-MEMBER
        no shutdown
        lag 2

    The quick version: FortiGate

    I assume that you have at least the default “fortilink” interface on your FortiGate. This interface is enabled for FortiLink, has a DHCP server attached, and is configured as an NTP server. If you need to first create a FortiLink interface, please refer to the documentation.

    On the FortiGate, our main objective is to prepare everything for the FortiSwitch, because we need to pre-authorize and pre-configure it. The reason is that once the FortiSwitch connects to the FortiGate via FortiLink, it will get created with a default configuration that will then get pushed onto the FortiSwitch. This default configuration won’t have any of the configuration we are going to make regarding the link to the third-party switch, so the FortiSwitch would pop up on the FortiGate and after the first config sync disappear, because it just loses its upstream connectivity.

    First, we create the VLAN interface, which we will later use for the trunk. This VLAN interface just needs a name, the parent interface and the ID. We don’t need an IP or anything else:

    VLAN interface config

    Next, we pre-authorize the FortiSwitch via its serial number:

    Pre-auth FortiSwitch

    Note: For some reason, my pre-authorized FortiSwitch was created with a configured speed of 10Mbit/s half-duplex on all ports. This might be a weird version thing, but check this yourself and set it to “Auto-negotiation” (you need to enable the “Configured speed” column first if you do it in the GUI).

    Auto negotiate from 10Mbps half-duplex

    As a final step on the FortiGate, we configure the LACP trunk port and the VLANs:

    FortiSwitch trunk creation
    VLAN configuration of trunk

    FortiGate config (quick)

    config system interface
        edit "VL_4084"
            set vdom "root"
            set interface "fortilink"
            set vlanid 4084
        next
    end
    config switch-controller managed-switch
        edit "S424ENTF12345678"
    	set sn "S424ENTF12345678"
    	set fsw-wan1-peer "fortilink"
    	set fsw-wan1-admin enable
        next
    end
    config switch-controller managed-switch
        edit "S424ENTF12345678"
            config ports
                edit "FORTILINK-L2"
                    set vlan "VL_4084"
                    set allowed-vlans-all enable
                    set type trunk
                    set mode lacp-active
                    set members "port2"
                next
            end
        next
    end

    With that, our FortiSwitch will get the correct configuration once it connects.

    The quick version: FortiSwitch

    I am starting with a factory default FortiSwitch that has only a password set, so I can log in.

    We are going to do much the same as on the FortiGate when preparing the FortiSwitch, so first, an LACP LAG trunk:

    config switch trunk
        edit "FORTILINK-L2"
            set mode lacp-active
            set members "port2"
        next
    end

    Then we configure the VLANs for the internal interface and the trunk to match the third-party switch’s VLANs:

    config switch interface
        edit "internal"
    	set native-vlan 4084
        next
        edit "FORTILINK-L2"
    	set native-vlan 4084
            set allowed-vlans 1-4094
        next
    end

    As a last step, we disable the auto topology feature. More on that in the detailed sections:

    config switch auto-network
        set status disable
    end

    With these things, our FortiSwitch should show up on the FortiGate and be fully manageable.

    FortiSwitch connected at layer 2

    And that’s it for the basics, but we’re not here for just the basics.

    What even is FortiLink?

    FortiLink is Fortinet’s proprietary protocol that is used to facilitate the management and onboarding of FortiSwitches. It is a combination of CAPWAP for management (there are alternatives for management), LACP for link establishment, LLDP for discovery, and some magic to tie all of it together and add more features on top of it.

    FortiLink is used both between a FortiGate and a FortiSwitch and also between FortiSwitches. The idea is that you connect a FortiSwitch to designated FortiLink ports on either a FortiGate or another FortiSwitch, and all the configuration you need to onboard the FortiSwitch happens automatically, so you spend less time onboarding and more time doing the relevant configuration.

    Basics of FortiLink

    Since FortiLink is proprietary, it will not work with third-party switches, so they always present a challenge, and the go-to answer is FortiLink over layer 3. I see this as a configuration you do out of necessity, i.e. if you use if you don’t have a layer 2 connection. Layer 3 has some limitations, which you can read about in the linked piece of documentation, and a layer 2 connection shouldn’t have them. I write “shouldn’t” because I have only tested the “No layer-2 data path component… “ and “FortiSwitch NAC is not supported” piece and that worked (note that if you have are doing layer 2 with a model, like an 108F, that can’t be directly connected to the FortiGate to use FortiSwitch NAC you still need another FortiSwitch in between).

    Why would one want to introduce a third-party switch?

    There can be a multitude of reasons why you can have a third-party switch somewhere in your infrastructure, as well as a FortiSwitch. The most likely reason is because of a migration. Imagine that you have a FortiGate, some third-party switches in your core, and you are now, as a first step, replacing the third-party access switches with FortiSwitches (later you might replace the core switches with FortiSwitches, but that’s a project for future you). In such a scenario, you can fully manage the FortiSwitches via a layer 2 connection and take advantage of the features right now.

    Is this stable? Does this survive a reboot?

    Yes, and yes, but with a pitfall.

    I had this running for over 3 hours, and the join time of the FortiSwitch didn’t change, and config syncs continued to function without problems.

    The pitfall with reboots is a feature called auto topology, and this feature, and the impact it has, created hours of frustration for me in writing this post. In the quick version, this feature got disabled, so reboots aren’t a problem, but disabling it makes it so that Inter-Switch-Links (ISLs) don’t form automatically between FortiSwitches.

    To understand why this feature creates problems, we have to first talk about how FortiLink uses VLANs, and then we get to auto topology.

    How FortiLink uses VLANs

    By default, the FortiLink VLAN on FortiOS is 4094. A FortiGate sends FortiLink communication untagged out of FortiLink interfaces, but, and this is really important, on the FortiSwitch side, this traffic, sourced by the virtual internal interface, egresses VLAN tagged out of the physical interface. This particular tagged VLAN behaviour is only relevant in a layer 2 configuration. In a regular FortiLink configuration, 4094 gets set as the native VLAN on ISLs. In practice, this means that the native VLAN of the internal interface needs to be covered by the allowed VLANs of the FortiSwitch <-> third-party switch trunk.

    The native VLAN that will be configured on the FortiSwitch <-> third-party switch trunk should match, and the native VLAN on the internal interface needs to match the FortiGate’s native VLAN, which is also the FortiLink VLAN, on the third-party switch’s trunk to the FortiGate. These two VLANs (native trunk VLAN and FortiLink VLAN) must be different. You can change the FortiLink VLAN on the FortiGate if you want, and if you want scalability for a layer 2 configuration with a third-party switch, you almost have to.

    config system interface
        edit fortilink
    	set switch-controller-mgmt-vlan XXXX
        next
    end

    This VLAN configuration will probably sound a bit confusing, so here is a diagram, with an adjusted FortiLink VLAN, to make it easier to understand:

    Diagram to show VLAN configuration

    You can pick any VLAN as the native VLAN on the FortiSwitch <-> third-party switch trunk, and again, it must be different from the FortiLink VLAN. “Any” isn’t strictly true, because 4094, on a default configuration, creates some problems in this type of layer 2 configuration, and I would also not use the 4088-4093 range, because FortiOS creates VLAN interfaces with these IDs for things like quarantine, RSPAN, etc. You can use these VLAN interfaces for the following configuration, but it’s ugly.

    I have tested changing the FortiLink VLAN in a regular FortiLink environment, where only FortiSwitches exist, and this didn’t create any connectivity problems, by the way, so this isn’t a dealbreaker when introducing layer 2 FortiSwitches behind a third-party switch.

    Now to auto topology.

    On auto topology

    The auto topology (or auto-network as it’s called in FortiSwitchOS) feature is enabled starting with FortiSwitchOS 7.2 and enables the auto-forming of ISLs between FortiSwitch units. This makes it easier to create a FortiSwitch topology because it turns into a plug-and-play scenario.

    On a default configuration, the management VLAN for auto topology on a FortiSwitch is set to 1, and once a FortiSwitch connects to a FortiGate, the value will be set to whatever the FortiGate has configured on its FortiLink interface on which the FortiSwitch connects.

    Auto topology also sets the native VLAN on the ISLs to the management VLAN.

    As an aside, auto topology might also be something you need to disable, or change the management VLAN of, on a standalone FortiSwitch deployment if your internal interface needs a different native VLAN than 1.

    In the quick version, we disabled auto topology. If you had it enabled, the native VLAN of the internal interface would get changed to the FortiLink VLAN defined on the FortiGate, and this breaks connectivity. Disabling auto topology creates another problem, which becomes clear when you read the documentation of the feature:

    “Use the auto topology feature to automatically form an inter-switch link (ISL) between two switches.”

    If we disable it, ISLs don’t get formed automatically between FortiSwitches, so we want auto topology enabled.

    If you look at the diagram above, I used VLAN 4083 for FortiLink, so you might ask:

    Why not VLAN 4094?

    This all boils down to two quirks of how FortiOS handles the 4094 VLAN and also the FortiLink VLAN.

    1. You cannot create a VLAN interface that matches the FortiLink VLAN, and you can’t change the FortiLink VLAN to the ID of an existing VLAN interface.
    2. Setting allowed VLANs to “all” on a FortiGate-managed FortiSwitch actually means a few different things, but never includes 4094.
    Error when setting the same management VLAN as an interface VLAN (GUI)
    Error when setting the same management VLAN as an interface VLAN (CLI)

    Point 1 is simple. If we could have a VLAN interface with ID 4094, we could configure this as the native VLAN everywhere, and this would be very simple, but without this interface, we can’t set the native VLAN on the FortiSwitch trunk (remember the FortiGate configures this trunk).

    Point 2 is devilish. FortiOS uses VLAN optimization for VLAN pruning. This is a nice feature, but the way it works is strange and also wrong. It’s wrong because it’s described as “applicable only to inter-switch link (ISL/ICL)”, but, from my testing, it also affects trunks you create manually, so it affects the configuration of our managed FortiSwitch.

    If you disable VLAN optimization you get a new option called “vlan-all-mode” with the options “defined” and “all”. “defined” sets the VLANs to whatever you have configured as FortiLink VLANs on the FortiGate. “all” should cover the full VLAN range of 1 to 4094, but the documentation, and the description in FortiOS, says “Include all possible VLANs (1-4093).”.

    All possible VLANs to set

    Notice how 4094 is missing from there. This absence is unrelated to the FortiLink VLAN. If you set it to something else, 4094 is still missing.

    Thanks to these two points, the FortiLink VLAN of 4094 creates the following chain of events on a default configuration:

    1. You have a working layer 2 configuration, and your FortiSwitch connects to the FortiGate
    2. The configuration gets synced to the FortiSwitch
    3. The auto-network/auto topology “mgmt-vlan” gets set to 4094
    4. The native VLAN of the internal interface gets set to 4094
    5. The allowed VLANs of the FortiSwitch trunk to the third-party switch get set to your configured VLANs, which never include 4094
      • If you disable VLAN optimization and set “vlan-all-mode” to “all”, the allowed VLANs are 1-4093
    6. The FortiSwitch loses connectivity and never regains it
      • Remember, the internal interface’s native VLAN gets sent out as tagged traffic on the physical interface.

    The auto topology feature, plus the way VLAN 4094 is handled, also creates problems with the plug-and-play functionality when you have another FortiSwitch connected to your layer 2-configured FortiSwitch.

    How to make this plug-and-play with another FortiSwitch

    I will now go through the entire configuration to enable the plug-and-play functionality you expect from FortiLink, but with a third-party switch directly connected to the FortiGate.

    Expanded lab topology

    Plug-and-play: FortiGate

    FortiGate config (plug-and-play)

    config system interface
        edit "VL_4084"
            set vdom "root"
            set interface "fortilink"
            set vlanid 4084
        next
    end
    config system interface
        edit fortilink
    	set switch-controller-mgmt-vlan 4083
        next
    end
    config switch-controller global
        set vlan-optimization none
        set vlan-all-mode all
    end
    config switch-controller managed-switch
        edit "S424ENTF12345678"
    	set sn "S424ENTF12345678"
    	set fsw-wan1-peer "fortilink"
    	set fsw-wan1-admin enable
        next
    end
    config switch-controller managed-switch
        edit "S424ENTF12345678"
            config ports
                edit "FORTILINK-L2"
                    set vlan "VL_4084"
                    set allowed-vlans-all enable
                    set type trunk
                    set mode lacp-active
                    set members "port2"
                next
            end
        next
    end
    1. We create the VLAN 4084 that gets used for the FortiSwitch’s native VLAN on the trunk
    2. We change the FortiLink management VLAN to 4083
    3. We disable VLAN optimization and set the allowed VLANs to all (1-4093)
    4. We pre-authorize the FortiSwitch
    5. We configure the FortiSwitch trunk

    The VLANs I picked can be any VLANs of your choosing, but all the caveats I explained still apply. It boils down to “Don’t use 4088-4094 and use different VLANs for each function”.

    Plug-and-play: Third-party switch

    Third-party switch config (plug-and-play)

    vlan 4083
        name FORTILINK-MGMT
    vlan 4084
        name FORTISWITCH-NATIVE
    interface lag 1
        description FORTIGATE-LAG
        no shutdown
        vlan trunk native 4083
        vlan trunk allowed all
        lacp mode active
    interface lag 2
        description FORTISWITCH-LAG
        no shutdown
        vlan trunk native 4084
        vlan trunk allowed all
        lacp mode active
    interface 1/1/1
        description FORTIGATE-LAG-MEMBER
        no shutdown
        lag 1
    interface 1/1/2
        description FORTISWITCH-LAG-MEMBER
        no shutdown
        lag 2
    1. We create a VLAN for FortiLink management and one for the FortiSwitch trunk
    2. We create an LACP LAG for the FortiGate with a native VLAN of 4083, which is the FortiLink management VLAN, and allow all VLANs
    3. We create an LACP LAG for the FortiSwitch with a native VLAN of 4084 and allow all VLANs
    4. We assign the physical ports to each LAG

    Plug-and-play: FortiSwitch

    FortiSwitch config (plug-and-play)

    config switch trunk
        edit "FORTILINK-L2"
            set mode lacp-active
            set members "port2"
        next
    end
    config switch interface
        edit "internal"
    	set native-vlan 4083
        next
        edit "FORTILINK-L2"
    	set native-vlan 4084
            set allowed-vlans 1-4094
        next
    end
    1. We create an LACP trunk with a member port
    2. We configure the internal interface with the native VLAN of 4083, which matches the FortiLink VLAN
    3. We configure the LACP LAG with a native VLAN of 4084 and allow all VLANs

    With this configuration, your layer 2 FortiSwitch will connect without issues to the FortiGate, sync configurations, and if you connect another FortiSwitch to the configured FortiSwitch, an ISL will automatically form, and it will just work.

    Again, the questions: Is this stable? Does this survive a reboot?

    Yes and yes. No caveats.

    I have also tested this with a third FortiSwitch hanging of the new FortiSwitch and didn’t notice any issues.

    I want to manually connect another FortiSwitch

    Let’s say you don’t care about all this plug-and-play stuff and the quick version is enough for you, but you still need another FortiSwitch connected and manageable. This requires a bit more legwork, but it is doable.

    There are five basic steps you have to do:

    1. Pre-authorize the new FortiSwitch (FortiGate)
    2. Manually create the trunk interfaces on both FortiSwitches with the same configuration on the FortiGate (FortiGate)
    3. Manually create the trunk interface with the correct VLANs on the new FortiSwitch (FortiSwitch)
    4. Disable auto topology on the new FortiSwitch (FortiSwitch)
    5. Manually set the native VLAN of the new FortiSwitch’s internal interface (FortiSwitch)

    FortiGate second FortiSwitch config (quick, steps 1-2)

    config switch-controller managed-switch
        edit "S108FPTV123456768"
    	set sn "S108FPTV123456768"
    	set fsw-wan1-peer "fortilink"
    	set fsw-wan1-admin enable
        next
    end
    config switch-controller managed-switch
        edit "S424ENTF12345678"
            config ports
                edit "FLINK-MANUAL"
                    set vlan "VL_4084"
                    set allowed-vlans-all enable
                    set type trunk
                    set mode lacp-active
                    set members "port1"
                next
            end
        next
        edit "S108FPTV123456768"
            config ports
                edit "FLINK-MANUAL"
                    set vlan "VL_4084"
                    set allowed-vlans-all enable
                    set type trunk
                    set mode lacp-active
                    set members "port1"
                next
            end
        next
    end

    FortiSwitch second FortiSwitch config (quick, steps 3-5)

    config switch auto-network
        set status disable
    end
    config switch trunk
        edit "FLINK-MANUAL"
            set mode lacp-active
            set members "port1"
        next
    end
    config switch interface
        edit "internal"
            set native-vlan 4084
        next
        edit "FLINK-MANUAL"
            set native-vlan 4084
            set allowed-vlans 1-4094
        next
    end

    Again, the questions: Is this stable? Does this survive a reboot?

    Yes and yes.

    What if my in-between switch is another FortiSwitch?

    Weird ask, but okay.

    Lab topology

    If you happen to have a FortiSwitch as your “third-party switch”, because it’s standalone, or managed by another FortiGate, the same configuration regarding VLANs, links (LACP or not), and trunks applies as with any other third-party switch, but you have to change the LLDP profile on your FortiSwitch’s port connecting to this third-party FortiSwitch from the default “default-auto-isl” profile to one without auto-ISL enabled, like the “default” profile. The third-party FortiSwitch doesn’t need to make any LLDP profile changes for this to work.

    LLDP profiles
    config switch physical-port
        edit port2
    	set lldp-profile default
        next
    end

    Again, the questions: Is this stable? Does this survive a reboot?

    Yes and yes. No caveats.

    More third-party switches

    I have also tested the following topology:

    More third-party switches

    Not much to say here. It works.

    Again, the questions: Is this stable? Does this survive a reboot?

    Yes and yes. No caveats.

    Wrapping up

    I wanted to make this post because I have not seen this topic being covered by anyone before, and it’s something that comes up from time to time, and most of the information on how to make it work is in a Reddit comment here, a Discord post there, etc. Now it’s hopefully condensed and easily accessible.

    I initially thought that this was going to be a quick thing that would take me about four hours from start to finish. In the end, it took me about 16 hours, because while getting the quick version done, the question “What if I want to add another FortiSwitch?” popped into my head and that sent me down the rabbit hole of auto topology, VLAN 4094 and more topology examples.

    I hope that this entire thing was interesting and hopefully helpful to you, dear reader.