I reviewed your original post and I see more clearly now.
It looks like your original approach would work except that your were trying to get the ghost player by accessing Player Controller 0 (which is always the first player on a given machine. So on your server, player controller 0 is the only player on that machine (the one you call player 1)
and on the client, player controller 0 is the only player on THAT machine (the one you call player 2)
so by using player controller 0 on the remote client you are getting the pawn for player 2 as your MyCharacter instead assigning Player 1 to it. So your display on Player 2’s computer will always show the ghost life value that Player 2 has, not Player 1.
To solve this, since you are (in the original post) storing ghost life as a replicated variable on Player 1’s pawn, you can probably just do the following:
On the pawn’s beginplay, detect if it is in the server world or the client world, and store that as a replicated variable.
In the widget constructor set a timer for every 1 or 2 seconds to trigger an event called RefreshGhost. In the event, loop through all the pawns until you find the one with that isServerPlayer variable set to true and assign that to MyCharacter. That way if the ghost pawn is ever destroyed and a new one created, the display will reassign to the new one instead of referencing the destroyed nonexistent one forever after. I use a timer because it slows things down to loop on a tick.
To improve performance you can forget the timer and instead add a reliable Multicast to the pawn’s OnPossess event which gets handled by the client and passes the Pawn’s playerstate’s PlayerId to the client which he can then loop over pawns and check playerstates until it finds the one with the matching ID and assign that to the myCharacter var. Then it doesnt have to keep checkingg. it just updates wenever a new pawn is created for the server player.
That should do it.