Q:

Que tecnología se usa para servir peticiones HTTP compatible con Python

Estoy montando una aplicación en AWS y bueno, este mundo es nuevo para mi.
Expongo el problema
Tengo experiencia con Apache/PHP, Apache es quien me ayuda a servir las peticiones HTTP y PHP es el lenguaje de Backend. 
El lenguaje de backend que estoy utilizando en este nuevo proyecto es Python, pero mi pregunta es ¿Cuál es la tecnología que me ayuda a servir las peticiones?
¿Puedo instalar Apache/Python, o cuál sería el dúo perfecto?
Se que esto puede tener muchas variantes dependiendo de cada experiencia y necesidades del proyecto, pero sinceramente estoy perdido en que instalar y que no.
Gracias por su orientación

A:

Parte python
Para la parte python es típico usar "micro-frameworks" que se ocupen de enrutar las peticiones, según la URL, a las funciones apropiadas. Estas funciones reciben parámetros, ejecutan una funcionalidad (típicamente consultas a bases de datos y transformaciones de los resultados a la forma necesaria para el cliente). 
Si quieres que el resultado sea una página HTML, suelen usarse mecanismos de "templates", que son algo parecido a lo que hace PHP, es decir, un fichero que parece HTML pero que en ciertas zonas tiene marcadores que señalan dónde deben volcarse los valores de ciertas variables. Python lee uno de esos templates, configura las variables, y llama a una función que retorna el HTML que se devuelve al cliente.
También es posible que el servicio no devuelva HTML para que sea visualizado en un navegador, sino sólo los datos para que el cliente los trate a su antojo. De este modo el cliente podría ser una aplicación móvil, por ejemplo. En este caso la tendencia es devolver los datos en JSON y diseñar la API siguiendo la filosofía REST.
Entre este tipo de microservicios, el más popular es Flask, combinado con jinja2 para los templates HTML. También se usa en ciertos entornos Bottle, que tiene la ventaja de que es un simple archivo python más fácil de instalar, pero mucho más limitado que Flask.
Últimamente están saliendo más frameworks similares, inspirados en Flask pero implementados usando el paradigma asíncrono (para Python 3.6+), como Vibora.
En principio estos frameworks son capaces de servir peticiones por sí solos, es decir, sin necesidad de poner "delante" un servidor como Apache. Simplemente se ejecutan con python y quedan escuchando en el puerto que les digas, al cual ya se podría conectar directamente el cliente, hacer sus peticiones HTTP y recibir la respuesta, ya sea en HTML o JSON. La respuesta podría ser simplemente un archivo HTML estático leído del disco, por lo que pueden reemplazar completamente a un servidor web estándar.
Servidor en producción
Si bien esto suele usarse durante el desarrollo, pues hace muy sencillo lanzar el servidor localmente para pruebas, una vez que quieras llevarlo a producción no se suele usar ya el mini-servidor incluído en el framework por cuestiones de rendimiento.
Por ejemplo, si usas Flask, éste está implementado en un único proceso y un único hilo. Esto implica que sólo puede atender a los clientes de uno en uno. Si un cliente hace una petición que tarda un poco en resolverse, los demás clientes que hayan llegado poco después tendrán que esperar su turno pues hasta que no se haya terminado de atender al primero no se pasará al siguiente. Esto es un problema especialmente si queremos usar algún mecanismo de "notificación push" hacia el cliente, como Long poll, Server Sent Events o WebSockets, ya que estas tecnologías requieren una conexión permanente con cada cliente, haciendo por tanto que sólo se pueda tener un cliente conectado. Los enfoques asíncronos pueden manejar varios clientes dentro de un solo hilo, pero son conceptualmente más complejos de programar y entender.
Por esto lo típico es que una aplicación de éstas sea ejecutada por otro entorno, que pueda lanzar varias en paralelo, en varios procesos y varios hilos dentro de cada proceso. 
WSGI
Desde hace ya muchos años, python tiene un "estándar" llamado WSGI acerca de cómo debe comunicarse un servidor de estos con la aplicación python que haya por debajo. Los frameworks antes mencionados son todos ellos compatibles con este estándar, lo que permite usar cualquiera de ellos con el servidor que elijas (que soporte también WSGI).
Por ejemplo, gunicorn sería un posible servidor (en este caso está también escrito en python) que se ocupa de cargar tu aplicación (Flask por ejemplo), e instanciarla varias veces, en varios hilos (también admite "green threads", que son por así decir falsos hilos, más ligeros, gestionados por gunicorn en lugar de ser hilos del operativo). Todo esto es transparente a tu aplicación que se programaría igual que si fuera a ejecutarse sola, excepto por la forma en que se arranca.
Otro posible servidor es uwsgi, en este caso escrito en C y por tanto más rápido que gunicorn.
Proxy (nginx)
Tanto si usas gunicorn como uwsgi como cualquier otro servidor compatible con WSGI, ese servidor quedará escuchando peticiones en cierto puerto. Aunque podrías hacer que ese puerto fuese el 80 y por tanto ya pueda recibir tráfico HTTP de internet, lo habitual es no hacerlo así, sino añadir otra capa intermedia más. Por ejemplo, tu servidor WSGI escucharía en el puerto 5000 (o el que quieras), y sólo admitiría conexiones desde localhost, y no desde Internet. 
En la misma máquina tendrías un servidor web estándar (Apache, o más frecuentemente nginx), que actuaría de proxy. 
Sería este servidor quien recibiría el tráfico desde internet (y podría ocuparse por ejemplo de los certificados y el protocolo HTTPS), podría servir archivos estáticos en ciertas carpetas y estaría configurado para que, cuando lleguen peticiones a una cierta URL, éstas sean redireccionadas al localhost:5000, donde estaría escuchando tu servidor WSGI.
Todo junto
Una combinación bastante típica sería tener nginx como servidor "dando la cara" a internet, atendiendo peticiones HTTP en el puerto 80 y/o HTTPS en el 443. Detrás de él estaría por ejemplo uwsgi escuchando en el puerto 5000 y nginx estaría configurado para que todas las peticiones a la ruta /myapp sean redirigidas a localhost:5000. Allí las recibe uwsgi y se las pasa a uno de los hilos/procesos que él mismo lanzó durante el arranque donde está Flask esperando peticiones (por el protocolo WSGI). Flask analiza la ruta concreta (ej: /myapp/usuario/22?q=foobar) y le pasa la petición a la función apropiada dentro de tu código python, la cual ya recibe los parámetros como una función python normal. La función puede retornar HTML o JSON, según te interese, y flask recogerá esa respuesta, la convertirá a una respuesta HTTP válida añadiendo las cabeceras necesarias que indican su tipo y se la pasará a uwsgi, el cual a su vez decidirá el método de transporte HTTP apropiado y añadirá alguna cabecera extra que pudiera hacer falta, enviando todo ello a nginx, el cual simplemente se la envía al cliente (quizás cifrándola antes si estamos usando HTTPS).
El esquema sería por tanto:
PETICION:
Cliente -[HTTPS]-> nginx:443 -[socket]-> uwsgi:5000 -[WSGI]-> Flask -[call]-> función python

RESPUESTA:
funcion python -[return]-> Flask -[WSGI]-> uwsgi -[socket]-> nginx -[HTTPS]-> cliente

Espero haberte ayudado a formarte una idea del panorama, que como ves es bastante diferente al del mundo PHP en el que es más típico que el mismo servidor web (Apache) pueda ejecutar el código (PHP) mediante un plugin o mod.
En Full Stack Python tienes muchísima más información sobre frameworks, WSGI, despliegue, servidores, etc.

