{"id":622,"date":"2020-11-23T19:32:24","date_gmt":"2020-11-23T19:32:24","guid":{"rendered":"https:\/\/dft.wiki\/?p=622"},"modified":"2026-06-09T13:27:49","modified_gmt":"2026-06-09T17:27:49","slug":"high-availability-with-carp-in-pfsense","status":"publish","type":"post","link":"https:\/\/dft.wiki\/?p=622","title":{"rendered":"High Availability with CARP and VRRP"},"content":{"rendered":"<p><strong>CARP<\/strong> (Common Address Redundancy Protocol) is an alternative protocol to <strong>VRRP<\/strong> (Virtual Router Redundancy Protocol) and the Cisco proprietary <strong>HSRP<\/strong> (Hot Standby Router Protocol).<\/p>\n<p><strong>BSD<\/strong> systems extensively use <strong>CARP<\/strong> while <strong>Linux<\/strong> systems prefer <strong>VRRP<\/strong>.<\/p>\n<p>The objective is to make two different gateways respond to the same IP. This is done by creating a Virtual IP, different from the IPs used by both routers, to decide which will be active and which will be on standby.<\/p>\n<p>In a network where two routers <code>10.0.0.2<\/code> and <code>10.0.0.3<\/code> communicate over CARP, they define which one responds to the Virtual IP <code>10.0.0.1<\/code>. When the active router becomes inoperative, the standby takes over.<\/p>\n<hr \/>\n<p><strong>ON PFSENSE WEB-UI<\/strong><\/p>\n<p>On the Master, go to <strong>Firewall &gt; Virtual IPs<\/strong>:<\/p>\n<ul>\n<li>Click &#8220;<strong>+ Add<\/strong>&#8220;,<\/li>\n<li>Set &#8220;<strong>Type<\/strong>&#8221; to &#8220;<strong>CARP<\/strong>&#8220;,<\/li>\n<li>Select the LAN &#8220;<strong>Interface<\/strong>&#8220;,<\/li>\n<li>Define the Virtual IP address in &#8220;<strong>Address(es)<\/strong>&#8220;, for example <code>10.0.0.1<\/code> with mask <code>\/24<\/code>,<\/li>\n<li>Define the &#8220;<strong>Virtual IP Password<\/strong>&#8220;,<\/li>\n<li>Leave the <strong>VHID<\/strong> as &#8216;<strong>1<\/strong>&#8216; for the first entry; if you already have a virtual IP, choose a different number,<\/li>\n<li>The &#8220;<strong>Description<\/strong>&#8221; can be &#8216;<strong>LAN Default Gateway<\/strong>&#8216;, for example,<\/li>\n<li>Click &#8220;<strong>Save<\/strong>&#8220;, then &#8220;<strong>Apply Changes<\/strong>&#8220;.<\/li>\n<\/ul>\n<p>If you configured HV Sync [<a href=\"https:\/\/dft.wiki\/?p=620\">Read It<\/a>], you do not need to repeat this on the Slave.<\/p>\n<p>If the Virtual IP was created for the WAN interface, go to <strong>Firewall &gt; NAT &gt; Outbound<\/strong>:<\/p>\n<ul>\n<li>Set &#8220;<strong>Outbound NAT Mode<\/strong>&#8221; to &#8220;<strong>Hybrid<\/strong>&#8220;,<\/li>\n<li>Click &#8220;<strong>Save<\/strong>&#8220;, then &#8220;<strong>Apply Changes<\/strong>&#8220;,<\/li>\n<li>Click &#8220;<strong>+ Add<\/strong>&#8220;,<\/li>\n<li>In the &#8220;<strong>Edit Advanced Outbound NAT Entry<\/strong>&#8221; table, set &#8220;<strong>Source<\/strong>&#8221; to the LAN network address, for example <code>10.0.0.0\/24<\/code>,<\/li>\n<li>Under &#8220;<strong>Translation<\/strong>&#8221; &gt; &#8220;<strong>Address<\/strong>&#8220;, select the &#8220;<strong>WAN Virtual IP<\/strong>&#8220;,<\/li>\n<li>Enter a &#8220;<strong>Description<\/strong>&#8220;, such as &#8216;<strong>WAN Virtual IP for NAT<\/strong>&#8216;,<\/li>\n<li>Click &#8220;<strong>Save<\/strong>&#8221; and &#8220;<strong>Apply Changes<\/strong>&#8220;.<\/li>\n<\/ul>\n<p>This prevents packet loss during the transition to the Slave.<\/p>\n<hr \/>\n<p><strong>ON LINUX<\/strong><\/p>\n<p>On Linux, VRRP can be implemented using <strong>KeepAliveD<\/strong> [<a href=\"https:\/\/github.com\/acassen\/keepalived\">link<\/a>].<\/p>\n<p>Install it on all redundant instances in the cluster.<\/p>\n<pre>sudo apt update\r\nsudo apt install keepalived -y\r\nsudo nano \/etc\/keepalived\/keepalived.conf<\/pre>\n<p>Configure all redundant instances as follows, assuming the interface name is <code>eth0<\/code>.<\/p>\n<p><strong>Primary<\/strong><\/p>\n<pre>vrrp_instance <strong>VirtualIP01<\/strong> {\r\n    state <strong>MASTER<\/strong>\r\n    interface <strong>eth0<\/strong>\r\n    virtual_router_id <strong>999<\/strong>\r\n    priority <strong>100<\/strong>\r\n    advert_int <strong>1<\/strong>\r\n    authentication {\r\n        auth_type PASS\r\n        auth_pass <strong>7bd3a2aa-f49b-11ef-8b04-ff74caed956a<\/strong>\r\n    }\r\n    virtual_ipaddress {\r\n        <strong>10.0.0.1<\/strong>\r\n    }\r\n}\r\n<\/pre>\n<p><strong>Backup<\/strong><\/p>\n<pre>vrrp_instance <strong>VirtualIP01<\/strong> {\r\n    state <strong>BACKUP<\/strong>\r\n    interface <strong>eth0<\/strong>\r\n    virtual_router_id <strong>999<\/strong>\r\n    priority <strong>90<\/strong>\r\n    advert_int <strong>1<\/strong>\r\n    authentication {\r\n        auth_type PASS\r\n        auth_pass <strong>7bd3a2aa-f49b-11ef-8b04-ff74caed956a<\/strong>\r\n    }\r\n    virtual_ipaddress {\r\n        <strong>10.0.0.1<\/strong>\r\n    }\r\n}<\/pre>\n<p><strong>Configuration<\/strong><\/p>\n<ul>\n<li><strong>VirtualIP01<\/strong> is an arbitrary name for this setup.\n<ul>\n<li>It helps identify the purpose of the configuration block in the file.<\/li>\n<\/ul>\n<\/li>\n<li><strong>MASTER<\/strong>\/<strong>BACKUP<\/strong> defines their roles at the initial state.\n<ul>\n<li>It determines which instance has authority over the active role.<\/li>\n<\/ul>\n<\/li>\n<li><strong>eth0<\/strong> is the interface name on each instance.\n<ul>\n<li>Interface names are tied to hardware and are specific to each instance.<\/li>\n<\/ul>\n<\/li>\n<li><strong>999<\/strong> is a shared ID that tells instances which virtual address(es) a relationship refers to.\n<ul>\n<li>Servers can have multiple relationships for different address(es).<\/li>\n<\/ul>\n<\/li>\n<li><strong>90<\/strong>\/<strong>100<\/strong> is the priority assigned to each instance to determine which has preference to be active.\n<ul>\n<li>Priority numbers are more meaningful when there are multiple backups.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Enable the service on all instances.<\/p>\n<pre>sudo systemctl enable keepalived --now\r\nsudo systemctl status keepalived\r\nip -4 -brief a<\/pre>\n<p>For more refined prioritization based on NGINX health, configure the master as follows.<\/p>\n<pre>vrrp_script <strong>Check_NGINX<\/strong> {\r\n    script \"<strong>\/usr\/bin\/pgrep nginx<\/strong>\"\r\n    interval <strong>2<\/strong>\r\n    weight <strong>-30<\/strong>\r\n}\r\n\r\nvrrp_instance <strong>VirtualIP01<\/strong> {\r\n    state <strong>MASTER<\/strong>\r\n    interface <strong>eth0<\/strong>\r\n    virtual_router_id <strong>999<\/strong>\r\n    priority <strong>100<\/strong>\r\n    advert_int <strong>1<\/strong>\r\n    authentication {\r\n        auth_type PASS\r\n        auth_pass <strong>7bd3a2aa-f49b-11ef-8b04-ff74caed956a<\/strong>\r\n    }\r\n    virtual_ipaddress {\r\n        <strong>10.0.0.1<\/strong>\r\n    }\r\n    track_script {\r\n        <strong>Check_NGINX<\/strong>\r\n    }\r\n}<\/pre>\n<p><strong>Note:<\/strong> the script <strong>Check_NGINX<\/strong> checks if NGINX is running every <strong>2<\/strong> seconds. If it fails, the priority of the <strong>MASTER<\/strong> instance drops by <strong>30<\/strong> (from 100 to 70), allowing the <strong>BACKUP<\/strong> instance, with a priority of <strong>90<\/strong>, to take over the virtual IP. It can also be configured to check interface status (down\/up), monitor a running process, or manage routes based on status (using <strong>virtual_routes<\/strong>).<\/p>\n<p><strong>Reflections<\/strong><\/p>\n<p>Keep in mind that while the second server is the backup for the first in one or more IPs, the first server can also be the backup for the second in other VRRP relationships. Multiple servers can relate to each other in many ways simultaneously.<\/p>\n<p>VRRP uses multicast by default, which raises security concerns in a shared broadcast domain (not recommended). Using unicast peer(s) does not eliminate the issue but provides more control over the communication. Replace <strong>X<\/strong> with the IP of the peer instance.<\/p>\n<pre>global_defs {\r\n    enable_script_security\r\n}\r\nvrrp_instance VirtualIP01 {\r\n    (...)\r\n    unicast_src_ip 10.0.0.<strong>Y<\/strong>\r\n    unicast_peer {\r\n        10.0.0.<strong>X<\/strong>\r\n    }\r\n    (...)\r\n}<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>CARP (Common Address Redundancy Protocol) is an alternative protocol to VRRP (Virtual Router Redundancy Protocol) [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1,8],"tags":[],"class_list":["post-622","post","type-post","status-publish","format-standard","hentry","category-ccna","category-pfsense"],"_links":{"self":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/622","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=622"}],"version-history":[{"count":11,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/622\/revisions"}],"predecessor-version":[{"id":5810,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/622\/revisions\/5810"}],"wp:attachment":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=622"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=622"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=622"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}