Milan, which had already qualified for the knockout stage, dominated but Danny scored in the 35th minute to ensure the Russian side finished ahead of Anderlecht in third place in Group C.
"The lads played well and deserved to win even though it was a bit of a nervous game," Spalletti said. "I'm happy to have qualified and happy with tonight's game as in the past two years we haven't won away from home, even when we've played well. However, even though we won, we could have done better. We should have closed the game earlier.
"I'd like to say a huge thank you to our fans tonight, as even I was stunned at the number who were here. Their number and enthusiasm tonight gives us extra responsibility. We have to work hard for them as they deserve it. Maybe a draw would have been a fairer result as we had to defend a lot, but we have to be happy, we're through. We'll try to do better.
Milan has only won four of its past 18 European games at home.
"I'm disappointed with the defeat because the team played a good game and we conceded in their only chance in the second half," Allegri said. "We need to be a bit more careful, we could have avoided the goal.
"We had several chances to level. But overall I'm happy with how the lads did. Zenit was obviously more hungry than us."
Milan looked set for a penalty in the fourth minute when a corner was cleared but only as far as Massimo Ambrosini, who headed it back in toward Pazzini in the six-yard box. Bruno Alves clambered all over Pazzini, falling on top of him as he attempted to clear, but the referee waved away Milan's furious claims for a penalty.
The home side slowly began to take control, and Urby Emanuelson went close with an effort from outside the area that was deflected wide of the right post.
From the resulting corner, Pazzini headed down to Zapata, who slid in to meet it at full stretch but fired off target from two meters out.
Bojan Krkic could have leveled in outrageous fashion five minutes later, however his overhead kick flew wide of the right post.
Milan again went close eight minutes after the break. Zenit goalkeeper Vyacheslav Malafeev pulled off a great save to deny Pazzini and the ball rolled tantalizingly in front of an open goal for Emanuelson, but it was cleared at the last second by a defender.
The Rossoneri should have leveled in the 75th when Bojan was released by a brilliant through-ball from Robinho and, although the Spaniard's effort was deflected, Pazzini was then millimeters from connecting with the ball, right in front of the open goal.
There were huge cheers as El Shaarawy came on with 10 minutes to go, with Milan going close with a curling effort from Robinho which flew wide of the right upright.