DEV Community

Cover image for "ngrok" from scratch
Sibelius Seraphini for Woovi

Posted on

"ngrok" from scratch

Introduction

ngrok is a fantastic tool for exposing local servers to the internet with minimal effort. However, it’s not always an ideal choice due to cost, licensing, or privacy concerns. In this article, we’ll recreate ngrok-like functionality using open-source tools: NGINX, Kubernetes, Docker, and OpenSSH. By the end, you'll have a custom, self-hosted tunnel that forwards traffic from the internet to your local machine.

Here’s a high-level overview of the architecture:

Archicture

Woovi’s Specific Needs for Tunneling

At Woovi, we developed a Shopify payment app that requires fixed URLs during development. Using ngrok presented a challenge because each developer generated a unique URL. Changing these URLs required re-submitting for Shopify’s review, even for development, causing significant delays.

To solve this problem, we created a solution that allows any developer to forward their local server to a consistent, custom domain, such as shopify.ourdomain.com. This eliminated the URL change issue, saving valuable time and improving the development workflow.

Setting Up OpenSSH + NGINX

The first step is to create a Docker image that includes both OpenSSH and NGINX. OpenSSH allows remote SSH connections, while NGINX will handle HTTP traffic forwarding.

Dockerfile

FROM alpine:latest

RUN apk add --no-cache \
    openssh \
    nginx \
    bash && \
    mkdir -p /run/nginx && \
    mkdir -p /root/.ssh

# Generate SSH host keys
RUN ssh-keygen -A

# Set the root password to '123456'
RUN echo "root:woovi" | chpasswd

RUN mkdir /var/run/sshd && \
    ssh-keygen -A && \
    echo "PermitRootLogin yes" >> /etc/ssh/sshd_config && \
    echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config && \
    echo "GatewayPorts yes" >> /etc/ssh/sshd_config && \
    echo "AllowTcpForwarding yes" >> /etc/ssh/sshd_config && \
    echo "PermitOpen any" >> /etc/ssh/sshd_config && \
    echo "MaxAuthTries 6" >> /etc/ssh/sshd_config && \
    echo "UseDNS no" >> /etc/ssh/sshd_config && \
    echo "AllowUsers root" >> /etc/ssh/sshd_config && \
    echo "TCPKeepAlive yes" >> /etc/ssh/sshd_config && \
    echo "ClientAliveInterval 60" >> /etc/ssh/sshd_config && \
    echo "ClientAliveCountMax 3" >> /etc/ssh/sshd_config && \
    sed -i '/^AllowTcpForwarding no$/d' /etc/ssh/sshd_config


# Create SSH directory for root user and set permissions
RUN mkdir -p /root/.ssh && chmod 700 /root/.ssh

RUN touch /root/.ssh/authorized_keys

COPY authorized_keys /root/.ssh/authorized_keys
RUN chmod 600 /root/.ssh/authorized_keys

COPY nginx.conf /etc/nginx/nginx.conf

# Expose port 22 for SSH
EXPOSE 22 80

# Start the SSH service
CMD /usr/sbin/sshd && nginx -g "daemon off;"
Enter fullscreen mode Exit fullscreen mode

This Dockerfile sets up an OpenSSH server alongside NGINX and exposes two ports:

  • Port 22: For SSH connections.
  • Port 80: For NGINX HTTP traffic.

nginx.conf

user nginx;
worker_processes auto;

error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    sendfile on;
    keepalive_timeout 65;

    server {
        listen 80;
        set_real_ip_from 0.0.0.0/0;

        server_name woovi-ssh;

        location / {
            proxy_pass http://localhost:5001;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

This configuration forwards all HTTP requests on port 80 to a local service running on port 5001. You’ll use this setup to forward traffic from your local machine to the remote server.

Forwarding Your Localhost to the Remote Server

Once the Docker container is deployed, you can forward your local server to the remote server using an SSH remote port forward. Run the following command:

ssh -R 5001:localhost:5001 root@myowndomain.com
Enter fullscreen mode Exit fullscreen mode

This command forwards requests from the remote server’s 5001 port to your local machine’s 5001 port. For example, accessing http://myowndomain.com/anypath will route traffic to http://localhost:5001/anypath on your machine.

Summary

By combining NGINX, OpenSSH, and Docker, you’ve created a self-hosted alternative to ngrok. This solution gives you complete control over your traffic without relying on third-party services, making it ideal for privacy-conscious developers and teams with specific tunneling needs.

Have you tried this setup? Let us know how it worked for you or share any questions in the comments!


Woovi is a fintech platform revolutionizing how businesses and developers handle payments in Brazil. Built with a developer-first mindset, Woovi simplifies integration with instant payment methods like Pix, enabling companies to receive payments seamlessly and automate financial workflows.

If you want to work with us, we are hiring!

Top comments (0)