Existem basicamente duas maneiras de encaminhar portas: Uma é o que seu pfSense está fazendo agora (NAT "completo", conntrack no Linux): Quando uma nova conexão é iniciada por um cliente, o pfSense cria um novo mapeamento em sua tabela NAT. troca o endereço de origem com o seu próprio, altera a porta de origem, se apropriado, e envia o pacote modificado para o seu servidor web. Seu servidor responderá automaticamente às respostas à máquina pfSense, que poderá então trocar os campos novamente e enviar o pacote ao cliente. A vantagem desta abordagem é que o seu servidor web não precisa estar ciente disso, apenas funciona. Tanto quanto me lembro, você pode desativar isso no pfSense se você mudar o seu modo NAT para "AON" e desabilitar o NAT para (webserverip, targetport).
Seu roteador consumidor fez uma simples porta de encaminhamento (DNAT no Linux): Na chegada de um pacote, ele simplesmente trocou o endereço de destino e enviou o pacote para o seu servidor. Como o pacote ainda tem o endereço de origem real, o servidor da web pode ver o endereço real do cliente. Infelizmente, quando ele envia uma resposta, ele coloca seu próprio endereço (privado) no campo de origem, que o roteador tem que trocar contra o seu IP público ao sair (SNAT no Linux). Como o servidor da Web endereça diretamente o pacote ao cliente, o roteador só pode fazer isso se também for o gateway padrão! (ou quando você configura políticas de roteamento bem funky em seu servidor web)