Skip to main content

GoPhish Installation and Phishing Simulation Setup

In this article, we will introduce how to install GoPhish on a local Ubuntu machine, publish it to the Internet through a Cloudflare Tunnel, and run a first phishing simulation campaign for security awareness training.

Updated 11 min readMarkdown
Part of seriesSecurity
GoPhish Installation and Phishing Simulation Setup

GoPhish is an open-source phishing toolkit for businesses and penetration testers. It lets you build email templates and landing pages, send campaigns to groups of users, and track who opened, clicked, submitted data or reported the email. It ships as a single Go binary with an embedded SQLite database, so it is easy to deploy and manage.

The result of this guide:

  • GoPhish runs on a local machine (a lab server, VM or mini PC) with no public IP and no inbound port opened on your firewall.
  • The phishing listener is published on a dedicated domain through a Cloudflare Tunnel; TLS is terminated at Cloudflare's edge.
  • The admin UI listens only on localhost and is never published.
  • Emails go out through an authenticated SMTP relay (Namecheap PrivateEmail in this example), with SPF/DKIM/DMARC aligned and the simulation allowlisted on the target's mail gateway.

Note: Run phishing simulations only with written authorization from the organization that owns the target mailboxes (scope, dates, target list, what data may be collected). Never collect real passwords: configure landing pages to capture the click and form submission only.

Architecture

The local machine opens no inbound port: cloudflared keeps an outbound connection to Cloudflare, which serves the landing page over TLS. Emails leave through the SMTP relay, and the admin UI never leaves localhost.

Installation Environment and Versions

  • Local machine: Ubuntu 24.04 LTS, 2 vCPU, 2 GB RAM, always on during the campaign (no laptop that goes to sleep)
  • Domain: registered at Namecheap, DNS hosted on Cloudflare (Free plan is enough)
  • Publishing: cloudflared (Cloudflare Tunnel)
  • Mail: Namecheap PrivateEmail SMTP (any authenticated relay works: Mailgun, Amazon SES, Microsoft 365)
  • GoPhish: v0.12.1 (releases)
Item Example value
Local machine gophish-lab (192.168.1.50, behind NAT)
Phishing domain secure-portal.example.net (Cloudflare Tunnel)
Sender mailbox it-notice@example.net (Namecheap PrivateEmail)
Admin UI 127.0.0.1:3333 (local only, never published)
Phishing listener 127.0.0.1:8080 (only reachable through the tunnel)

Use a domain you control and that is clearly yours. Do not register look-alike domains of a real third-party brand.

Move the Domain DNS to Cloudflare

Cloudflare Tunnel needs the domain's DNS on Cloudflare. Add the domain in the Cloudflare dashboard (Free plan), then in Namecheap → Domain List → Manage → Nameservers choose Custom DNS and enter the two nameservers Cloudflare assigned. Wait until the domain shows Active in Cloudflare.

The local machine only needs outbound access to Cloudflare (TCP/UDP 7844 for the tunnel, 443 for the API), plus outbound 465 or 587 to the SMTP relay. Nothing is opened inbound on your router or firewall.

Note: Cloudflare actively scans for phishing on its network and may show a warning page or suspend the hostname, even for an authorized simulation. Keep the written authorization at hand, use your own organization's branding (never a third-party brand), keep campaigns short, and remove the hostname when the campaign ends.

Download and Install GoPhish

Create a dedicated user and install the binary under /opt/gophish:

sudo apt-get update && sudo apt-get install -y unzip
sudo useradd -r -m -d /opt/gophish -s /usr/sbin/nologin gophish

cd /tmp
wget https://github.com/gophish/gophish/releases/download/v0.12.1/gophish-v0.12.1-linux-64bit.zip
sudo unzip gophish-v0.12.1-linux-64bit.zip -d /opt/gophish
sudo chmod +x /opt/gophish/gophish
sudo chown -R gophish:gophish /opt/gophish

Note: Check the release page for checksums and a newer version before you install. The asset name format above matches v0.12.1.

GoPhish Configuration

Configure config.json

Bind both listeners to localhost: the admin UI stays private, and cloudflared publishes only the phishing listener.

sudo -u gophish vim /opt/gophish/config.json
{
  "admin_server": {
    "listen_url": "127.0.0.1:3333",
    "use_tls": true,
    "cert_path": "gophish_admin.crt",
    "key_path": "gophish_admin.key",
    "trusted_origins": []
  },
  "phish_server": {
    "listen_url": "127.0.0.1:8080",
    "use_tls": false,
    "cert_path": "example.crt",
    "key_path": "example.key"
  },
  "db_name": "sqlite3",
  "db_path": "gophish.db",
  "migrations_prefix": "db/db_",
  "contact_address": "security-awareness@example.net",
  "logging": {
    "filename": "",
    "level": ""
  }
}
  • contact_address is added to every email as the X-Gophish-Contact header, so a recipient or mail admin can report the simulation.
  • trusted_origins (new in v0.12.1) is only needed if you later publish the admin UI behind a reverse proxy on another hostname.
  • The admin certificate is self-signed and generated automatically on first start.

Run as a systemd Service

GoPhish uses relative paths, so WorkingDirectory is required:

sudo tee /etc/systemd/system/gophish.service > /dev/null <<'EOF'
[Unit]
Description=GoPhish phishing simulation
After=network-online.target

[Service]
Type=simple
User=gophish
Group=gophish
WorkingDirectory=/opt/gophish
ExecStart=/opt/gophish/gophish
Restart=on-failure
NoNewPrivileges=true
PrivateTmp=true

[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now gophish

Since v0.11 there is no default password. The initial admin password is generated randomly and printed in the log on first launch:

sudo journalctl -u gophish | grep -i "password"
==============================================================================
... Please login with the username admin and the password <random_password>

Access the Admin UI

On the local machine (or from another host on the LAN through ssh -L 3333:127.0.0.1:3333 user@192.168.1.50), browse to https://127.0.0.1:3333 and accept the self-signed certificate.

Log in with admin and the generated password. GoPhish forces a password change at first login. Then create one account per operator under User Management instead of sharing admin.

Publish the Phishing Listener with Cloudflare Tunnel

Install cloudflared from Cloudflare's APT repository:

sudo mkdir -p --mode=0755 /usr/share/keyrings
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg > /dev/null
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared any main' | sudo tee /etc/apt/sources.list.d/cloudflared.list
sudo apt-get update && sudo apt-get install -y cloudflared

Authenticate, create a named tunnel and route the hostname to it (this creates a proxied CNAME in Cloudflare DNS):

cloudflared tunnel login                      # opens a browser, pick example.net
cloudflared tunnel create gophish
==============================================================================
Created tunnel gophish with id <TUNNEL_ID>
cloudflared tunnel route dns gophish secure-portal.example.net

Create the tunnel configuration. Only the phishing listener is published; everything else returns 404:

sudo mkdir -p /etc/cloudflared
sudo cp ~/.cloudflared/<TUNNEL_ID>.json /etc/cloudflared/
sudo tee /etc/cloudflared/config.yml > /dev/null <<'EOF'
tunnel: <TUNNEL_ID>
credentials-file: /etc/cloudflared/<TUNNEL_ID>.json

ingress:
  - hostname: secure-portal.example.net
    service: http://127.0.0.1:8080
  - service: http_status:404
EOF

Run it as a service and verify:

sudo cloudflared service install
sudo systemctl enable --now cloudflared
cloudflared tunnel info gophish
curl -sI https://secure-portal.example.net | head -1

In the Cloudflare dashboard, set SSL/TLS → Edge Certificates → Always Use HTTPS to on. The origin stays plain HTTP on 127.0.0.1:8080, which never leaves the machine.

Note: Never add 127.0.0.1:3333 to the ingress rules. If remote admin access is really needed, publish it on a separate hostname protected by Cloudflare Access (SSO/OTP policy), and add that hostname to trusted_origins in config.json, otherwise GoPhish rejects the login with a CSRF error.

Note: Behind the tunnel, GoPhish may record 127.0.0.1 as the client IP. Cloudflare sends the real address in CF-Connecting-IP and X-Forwarded-For; check what your GoPhish version stores after the first test campaign.

Mail Delivery

DNS is where most phishing simulations fail: if SPF, DKIM and DMARC are wrong, the emails never reach the inbox and the campaign measures your mail gateway instead of your users.

DNS Records on Cloudflare

Since the nameservers now point to Cloudflare, mail records are added in Cloudflare → DNS → Records (not in Namecheap Advanced DNS anymore). The CNAME for the landing page was created by cloudflared tunnel route dns. Copy the exact PrivateEmail values from your PrivateEmail panel. Mail records must be DNS only (grey cloud).

Type Name Value Purpose
CNAME (proxied) secure-portal <TUNNEL_ID>.cfargotunnel.com Landing page through the tunnel (auto-created)
MX @ mx1.privateemail.com / mx2.privateemail.com Mailbox for replies and bounces
TXT @ v=spf1 include:spf.privateemail.com ~all SPF: who may send for the domain
TXT default._domainkey (key from PrivateEmail → DKIM) DKIM signature
TXT _dmarc v=DMARC1; p=none; rua=mailto:dmarc@example.net; fo=1 DMARC monitoring and reports

Check propagation before going further:

dig +short secure-portal.example.net          # Cloudflare edge IPs (proxied)
dig +short MX example.net
dig +short TXT example.net
dig +short TXT default._domainkey.example.net
dig +short TXT _dmarc.example.net

Note: Use a new domain for the simulation, not your production domain, and let it age a few days before the first campaign. Brand-new domains are often flagged by mail and web filters.

Sending Profile

In GoPhish → Sending Profiles → New Profile:

Field Value
Name PrivateEmail - it-notice
From IT Service Desk <it-notice@example.net>
Host mail.privateemail.com:465 (or :587 with STARTTLS)
Username / Password PrivateEmail mailbox credentials
Ignore Certificate Errors Unchecked

The From address must be on the same domain that SPF and DKIM cover, otherwise DMARC alignment fails. Click Send Test Email to your own mailbox and check the headers: spf=pass, dkim=pass, dmarc=pass.

Allowlist the Simulation on the Target Mail Gateway

For an internal awareness program, the goal is to test people, not to bypass the email filters. Ask the mail administrator of the target organization to allowlist the simulation, for example:

  • Microsoft 365: Defender portal → Email & collaboration → Policies → Advanced delivery → Phishing simulation (sending domain, sending IP of the relay, simulation URL).
  • Google Workspace: an inbound gateway / spam allowlist rule for the sending domain or IP.
  • On-premise gateways (FortiMail, Proofpoint, Cisco...): bypass rule for the sending IP and domain, and URL rewriting / sandbox exclusion for the phishing domain, so automated link scanners do not create false clicks.

Keep the X-Gophish-Contact header. It lets SOC analysts identify the simulation quickly if a user reports the email.

Run a Campaign

A campaign combines five objects. Create them in this order in the admin UI.

1. Users & Groups

Users & Groups → New Group, then add users manually or import a CSV with this header:

First Name,Last Name,Email,Position
An,Nguyen,an.nguyen@target.example,Accountant
Binh,Tran,binh.tran@target.example,HR Officer

Start with a small pilot group (IT and security staff) to validate delivery and tracking before the real target list.

2. Email Templates

Email Templates → New Template: set a name, subject and HTML body. The important template variables are:

Variable Meaning
{{.URL}} Unique tracking link for each recipient (required)
{{.Tracker}} Invisible image that records the "Email Opened" event
{{.FirstName}}, {{.LastName}}, {{.Position}} Personalization from the group CSV

Keep Add Tracking Image enabled. Build scenarios that match your training goals (password expiry, shared document, delivery notice) using your own organization's context, not a third-party brand.

3. Landing Pages

Landing Pages → New Page, paste your HTML or use Import Site on a page you own.

  • Enable Capture Submitted Data to record that a user submitted the form.
  • Leave Capture Passwords disabled. GoPhish then stores the event without the password value, which is enough to measure behavior and avoids holding real credentials.
  • Set Redirect to an internal awareness page that explains the warning signs the user missed.

4. Sending Profile

Use the profile created in Mail Delivery.

5. Campaigns

Campaigns → New Campaign:

Field Value
Email Template / Landing Page / Sending Profile The objects created above
URL https://secure-portal.example.net
Launch Date Agreed start time
Send Emails By Spread over 1–2 hours to avoid rate limits and bursts
Groups Target group

Click Launch Campaign.

Read the Results

The campaign page shows a timeline per recipient and these counters:

Event What it tells you
Email Sent Delivery attempt accepted by the relay
Email Opened Tracking image loaded (undercounted when images are blocked)
Clicked Link User opened {{.URL}}
Submitted Data User submitted the landing page form
Email Reported User reported the email (via a report button integration calling GoPhish's report endpoint)

The most useful awareness metrics are the click rate, the submit rate and the report rate. Export results as CSV (Export CSV on the campaign page) for the report, and treat them as personal data.

Conclusion

I introduced a way to run GoPhish on a local machine and publish only its landing pages through a Cloudflare Tunnel, without a cloud VM, a public IP or any inbound firewall rule. Combined with aligned SPF/DKIM/DMARC and an allowlist on the mail gateway, the campaign measures what matters: how users react to a phishing email. Hope you find it helpful!

No comments yet. Be the first to comment.