How to Setup GoPhish on Docker With an NGINX Reverse Proxy and MySQL

Production-Ready Setup

Why would I ever want to do this?

Reproduce and transport an open-source phishing setup if your client needs security.

Building the NGINX container

Install docker if you haven’t. Start your NGINX container with the following:

docker run --name reverse_proxy -dit -p 80:80 -p 443:443 nginx

This will start the container, named reverse_proxy, with ports 80/443 exposed to the outside world. When you hit the host’s ip at one of those ports, you’ll be talking to NGINX. Next, let’s get into this container with the following command:

docker exec -it reverse_proxy bash

This will give you a shell into the container. We’ll need to grab Certbot now, because LetsEncrypt is amazing and will do a ton of legwork for us. Run the following in the shell:

sudo apt update
sudo apt install python3-acme python3-certbot python3-mock python3-openssl python3-pkg-resources python3-pyparsing python3-zope.interface
sudo apt install python3-certbot-nginx

Generating SSL certificates

First, let’s create a new config named yourwebsitename_com.conf (or whatever your domain is called) inside /etc/nginx/conf.d/ and put the following code inside:

 listen 80;
 server_name; location / {

And then restart NGINX: service nginx restart. Note: the proxy_pass directive should be set to the local IP of the GoPhish server. I’ll cover how to manually set the IP later, check this link out for more information.

When you run the NGINX restart command, the shell will close because this container restarts when the NGINX service restarts. Get back into the shell and run the following:

certbot --nginx

Follow the on-screen prompts that will ask which domain you want to setup SSL certs for, along with some other important options. When asked if you’d like to redirect HTTP, HTTPS Only, etc…, choose to redirect HTTP to HTTPS. Certbot will generate the SSL cert and also modify the NGINX config to redirect HTTP -> HTTPS while preserving your internal routing. Restart NGINX again, and you should be rolling. You can test the config from within the container with nginx -t .

Setting up GoPhish

We’re going to pull the latestGoPhish docker image totart this process. We’ll want to have a predictable IP address, since NGINX has to know where to send traffic, and this time we do not want to expose any ports on the host machine. Run the following command to get GoPhish rolling:

docker run -dit --ip -p 3333:3333 --name gophish_prod gophish/gophish

Now GoPhish is running, with the phisher server only exposed in the virtual docker network (, and reachable only by other programs/containers locally. I’ve exposed port 3333 so you can still reach the admin UI by hitting the ip:port directly. If you’ve used GoPhish in the past, you might be wondering why I haven’t even looked at config.json yet. Well, here’s what comes with the GoPhish docker image:

 "admin_server": {
 "listen_url": "",
 "use_tls": true,
 "cert_path": "gophish_admin.crt",
 "key_path": "gophish_admin.key"
 "phish_server": {
 "listen_url": "",
 "use_tls": false,
 "cert_path": "example.crt",
 "key_path": "example.key"
 "db_name": "sqlite3",
 "db_path": "gophish.db",
 "migrations_prefix": "db/db_",
 "contact_address": "",
 "logging": {
 "filename": "",
 "level": ""

Looks like we have the admin interface running on 3333, and the phish server on port 80. I cheated and read ahead, so there’s nothing you’ll have to change to get to the admin interface or allow targets to hit the phish server. To use MySQL, instead of the sqlite default, run the following commands from the host:

docker exec gophish_prod sed -i 's|sqlite3|mysql|g' config.jsondocker exec gophish_prod sed -i 's|gophish.db|gophish:password@(|g' config.json

The first command switches the database type to mysql, the second provides the credentials and host address for the database. The format is:


Set up MySQL

Now let’s setup the database, to get the database container running:

docker run -dit --ip -e MYSQL_ROOT_PASSWORD=password --name gophish_db mysql 

Now, get into the database, using the root password you just set:

docker exec gophish_db mysql -u root -p

and run the following:

mysql> CREATE USER gophish@'' IDENTIFIED BY 'password'mysql> CREATE DATABASE gophish CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;mysql> GRANT ALL PRIVILEGES ON gophish.* TO gophish@'' WITH GRANT OPTION;mysql> SET GLOBAL CONFIG

Now, exit mysql and let’s alter the mysql config to allow invalid dates, because MySQL doesn’t like how we’re going to be saving campaign dates:

docker exec gophish_db echo '[mysqld]\n sql_mode=ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' >> /etc/mysql/my.cnf && service mysql restart

You now have a MySQL database ready to accept connections from your GoPhish instance. Now let’s get GoPhish restarted and running with MySQL:

docker restart gophish_prod
Vadim Iljin
Vadim Iljin

My research interests include Security, SEO, OSINT and BI.