Mitmproxy through Docker
By Neosb
Published: 2025-02-25 19:12
Last Modified: 2025-03-17 01:31
Tags: dockerethical hackingbughuntingmitmproxyweb-development
Using Mitmproxy in Docker container
UPDATED on 2025-03-17 01:31:00.98401443 +0000
Why?
Using Docker or Podman (somehow a docker command equivalent) and with Podman Desktop, almost a Docker Desktop, you can abstract your commands into another layer, securing your host OS from unintentional failures, and thus safe-proof your transparent proxy journey. Although the commands written into terminal are not simple and easy to understand in the first place, they might get you going further along the way of abstracting even more, like using devcontainers in VS Code, and even if you're not intend to use Visual Studio Code for development purposes, you might as well use it as just a devcontainer server... And I will show you just that and more, in this text.
Simple steps to open mitmproxy and run http/s requests and responses through it, but inside container
Refresher on Mitmproxy from previous setup post (maybe you prefare bare metal)
Previous post on setting up Mitmproxy
If you need a refresher on what Mitmproxy is, or why you might be using it, the link up here is where you might find some more answers, but in short, it's a transparent proxy inteded for use with web applications, and web requests you send with programs like Postman, Httpie or simply curl. It allows you to intercep, inspect and modify the request and response of them so you might do anything you can imagine to your App, API or whatever.
For testing purposes in this article I creat my_network docker network
To create a network, in which you can connect in between docker containers, so that I can emulate a real world scenario, like connecting to webserver, or a website I use this docker command:
Language: sh
docker network create my_network
Starting mitmproxy in Docker or Podman
If you're here to watch - youtube like introduction to mitmproxy in docker container
So you, don't have time to read, right? You like the youtube, right? OK. Here you go!
But first, check your "local" config
Why?
You might want to preserve configuration of your docker containers, so to do just that
save a config file on your host machine, and include it in every invocations of
docker run command. There you can also find certificates files, so you don't have to manually add the after each re-run of the docker containers. I did not find the way to have many, of mitmproxy instances at once with the same certificates, but with different? No
problem, just save your configuration files in other folder, and you're done - just
don't forget to change the attached folder to the other...
How?
Create, if it does not exist, folder named ~/.mitmproxy and in there create, if it does
not already exist, a config file named config.yml. In there you can put your
configurations. The documentation for your possibilities.
For me it's just this:
Language: yaml
# Port on which the http proxy will be listening
# I want it to be distinct, so it's outside of usual web apps range
listen_port: 8899
Then in some terminal multiplexer like tmux or zellij or terminal emulator in such of kitty or warp run your new docker commads... We will be using docker run --rm
syntax so it also removes the container after it's stopped, but you might omit that to
preserve logs, or add some more functionality to mitmproxy or mitmdump using Python,
but for now we will just stick to simple things like running your first request. And action!
Run mitmproxy in docker container
Language: bash
docker run --rm -it -v ~/.mitmproxy:/home/mitmproxy/.mitmproxy -p 8899:8899 --network my-network --name proxy mitmproxy/mitmproxy
It's as simple as that. This will fetch the latest build of mitmproxy from hub.docker.com,
or rather docker.io and then run the Dockerfile it's build with, which in our case will
run the mitmproxy with specifide configuration files in ~/.mitmproxy folder and
certificates stored there (it will create new for us, if there is none).
You might want to quickly inspect the following website, where the developers of mitmproxy
post their work on Docker Hub. I will cover mitmproxy, the mitmdump and mitmweb is out
of scope of this article.
What I can do now?
Now you're basically done. Cooked. Frag out!
From now on, you can refer to your mitmproxy instance proxy as http://localhost:8899 for example using curl to connect to this website:
Language: sh
curl -x http://localhost:8899 https://neosb.net/blog/mitmproxy-through-docker --insecure
Run nginx server in docker container
To show you some examples of usage, I will first containerize nginx server in
another tab, pane or terminal. You can skip this part and confidently start using
mitmproxy, even with your browser. To do it, visit website http://mitm.it and follow on the guide to install the required certificates for your web broweser (Firefox is recommended), or operationg system. Then install FoxyProxy
if you used Firefox and set it up for the host: localhost, port: 8899 switch the
proxy on... But hey, we're talking nginx here...
Language: bash
docker run --rm --network my-network -p 9999:80 --name webserver nginx:latest
Now that you have a server in my network, you can refer to it as webserver from other docker containers, and proxy:8899 to connect through proxy using alpine/curl container. I will show it to you how...
Now the meat with HTTPie and curl
Run HTTP request using HTTPie in docker container
Let's say that first, you want to test how the httpie works in docker.
Language: bash
docker run --rm -v ~/.httpie:/root/.httpie --network my-network --env HTTP_PROXY="http://proxy:8899" --env HTTPS_PROXY="http://proxy:8899" alpine/httpie GET webserver --body --verify=no
This is full command, you should use to test ANY webserver, you can switch webserver into any domain. I will show it later, now let's just run it, and see how
flows are populating mitmproxy. As it should. You might even want to remove --body
from this invocation, because in default settings, httpie outputs also headers.
HTTP request using curl in docker container
Language: bash
docker run --rm --network my-network --env HTTP_PROXY="http://proxy:8899" --env HTTPS_PROXY="http://proxy:8899" alpine/curl --silent --insecure webserver
The above code does completely the same thing that we have done previosly with httpie. We just do it in curl, it more widely adopted, so you might find answers
quickly for your qeustions using curl. The choice is yours, output is similar. We
can check this with:
Ensure we have got exactly the same output from HTTPia that in curl
Language: bash
diff <(docker run --rm -v ~/.httpie:/root/.httpie --network my-network --env HTTP_PROXY="http://proxy:8899" --env HTTPS_PROXY="http://proxy:8899" alpine/httpie GET webserver --body --verify=no) \
<(docker run --rm --network my-network --env HTTP_PROXY="http://proxy:8899" --env HTTPS_PROXY="http://proxy:8899" alpine/curl --silent --insecure webserver)
What is the difference?
HTTPie has it's own GUI app, httpie in commandline interface has different syntax, you could say - easier to grasp. Nevertheless, using one over another is not an option since the key to getting nailed you request is not the hammer, you need the payload - the request, and how you get it - it's up to you 🚀
HTTPS request with HTTPie in docker container to JSON endpoint with jq parsing
Now, let's move to something a little bit less trivial. We want to pars a JSON output. How to do it? We can use a jq parser, that will let us easily travers through many branches and trees. For starters, I will GET from the Internet, dummy
/hello endpoint of httpie.io website. There is some JSON! So let's get dirty with it...
Language: bash
docker run --rm -v ~/.httpie:/root/.httpie --entrypoint=https --network my-network --env HTTP_PROXY="http://proxy:8899" --env HTTPS_PROXY="http://proxy:8899" alpine/httpie GET httpie.io/hello --body --verify=no | docker run --rm -i backplane/jq ".links .homepage"
Like you see, we have got back the base address where the HTTPie can be found. And now, I will explain somethig. You can get a field refering to it with .field_name syntax, and I have got deep into 2-levels finding the .homepage in .links.
HTTPS request with curl in docker container to JSON endpoint with jq parsing
Language: bash
docker run --rm --network my-network --env HTTP_PROXY="http://proxy:8899" --env HTTPS_PROXY="http://proxy:8899" alpine/curl --silent --insecure https://httpie.io/hello | docker run --rm -i backplane/jq "."
While you don't alway know the name of the fields, or how many elements, there is in an array, or the overall structure of the JSON, you would want then to invoke the jq with "." argument, and even maybe saving it first as a reference for the future with backplane/jq "." > my_json.json.
Summary
It's the most popular way to get things done, but it can be done, as you see now. I've always wanted to work with Docker, err... Podman... Desktop... Whatever.
Securing your host system with another layer of abstraction is a shiny feature, however, I could not get the mitmweb working, and we didn't touched on the mitmdump mode, but still putting mitmproxy into a docker container is not bad at all, and it might the thing you expect from modern transparent proxy in terminal (CLI).
