devilbox / docker-ngrok

MIT License
9 stars 9 forks source link

Subdomain support for ngrok #5

Open ryandroid226 opened 4 years ago

ryandroid226 commented 4 years ago

Hi @cytopia, I would like to request subdomain support for the ngrok container. I believe this could be implemented by making a few small edits to the docker-entrypoint.sh file, under the HTTP TUNNELS section. The third example under this link shows how the subdomain is added to the config.

ryandroid226 commented 4 years ago

I have been working on the entrypoint and made some edits that have the subdomain option working. The only problem I see right now is that the user is required to add a fourth parameter value of "auto" even if they don't want to use the subdomain. The tunnel attribute with my solution adds on an additional parameter at the end so that there are 4 parameters, each separated by colons. See below.


for tunnel in ${HTTP_TUNNELS}; do
    i=$((i+1))
    # Ensure each tunnel line has the correct format: <string>:<string>:<string>:<string>
    if [ "$( echo "${tunnel}" | sed 's/:/:\n/g' | grep -c ':' )" -ne "3" ]; then
        >&2 echo "[ERROR] Wrong format in tunnel line: '${tunnel}'"
        >&2 echo "[ERROR] Should be: <domain>:<backend_addr>:<backend_port>:<ngrok_subdomain>"
        exit 1
    fi
    domain_name="$(  echo "${tunnel}" | awk -F':' '{print $1}' )"
    backend_addr="$( echo "${tunnel}" | awk -F':' '{print $2}' )"
    backend_port="$( echo "${tunnel}" | awk -F':' '{print $3}' )"
    ngrok_subdomain="$( echo "${tunnel}" | awk -F':' '{print $4}' )"

    # Append to ngrok config
    {
        echo "  tunnel_${i}:"
        echo "    addr: ${backend_addr}:${backend_port}"
        echo "    host_header: \"${domain_name}\""
        echo "    proto: http"
        if [ $ngrok_subdomain != "auto" ]; then
        echo "    subdomain: ${ngrok_subdomain}"
        fi

    } >> "${CONFIG_FILE}"

done
miquelbrazil commented 4 years ago

Hey @ryandroid226, I coincidentally began looking at how to extend the devilbox/docker-ngrok container to support subdomains earlier this week. Your solution has allowed me to keep moving forward with my current project but I'd also like something more durable. Thanks for your insight.

For what it's worth, an initial approach I had taken was to add my subdomain-ed tunnels directly to the ngrok.yml file rather than patching docker-entrypoint.sh. The docker-compose.override.yml-ngrok includes a default tunnel anyway with httpd:httpd:80 so you avoid triggering the sanity check if you don't include HTTP_TUNNELS in your .env file. Unfortunately, my bash-scripting-foo isn't quite up to the challenge of coming up with a complete solution just yet, but I've gotten started by forking this repo and pushing it to my own DockerHub account until I can hopefully find the time to submit back my first ever open-source pull request at some point over the upcoming long weekend.

I'll also add, I've been examining the code/issues on wernight/docker-ngrok as a point of reference on how we might address this here.

ryandroid226 commented 4 years ago

Hey @miquelbrazil, I'm glad to see someone else has interest in subdomain support for this ngrok container!

I've thought of two ways to make this work a little better but my bash-scripting-foo is pretty weak as well. The first way would involve adding a check earlier on in the script that would allow 3 OR 4 parameters so that the parameter is simply optional. However, I don't think the subdomain really belongs where I placed it. I think it would be better suited as an additional parameter in the .env file with some type of indicator as to which tunnel the subdomain belongs to since there is the option to handle multiple tunnels. Maybe this is as simple as adding a subdomain variable to the .env file and just passing an empty string if no subdomain is needed. For example, if you have HTTP_TUNNELS=project1.loc:localhost:8080,project2.loc:apache:80 as your HTTP_TUNNELS variable but only wanted a subdomain for project2.loc then we could have HTTP_SUBDOMAINS=,project2.ngrok.io.

I'm probably going to try a few things within the next couple of days to see if I can come up with something a little more elegant but I'm also interested to see what you come up with so I'll keep a look out for that pull request.

miquelbrazil commented 4 years ago

I actually think including the subdomain in the tunnel string is a good approach. This allows the subdomain to remain matched to the project and not present when it isn't necessary for that tunnel. Including the subdomain as a separate .env parameter feels like it would get tricky pretty quickly when you now have to match it to a domain supplied in another variable.

An obvious format would be to include the subdomain as part of the virtual host domain (i.e. subdomain.project1.loc:localhost:8080). The problem is Devilbox would currently parse that as a full domain and expect the project directory to be subdomain.project1 (this closed issue on the Devilbox repo shows how that would interfere with the default strategy for using wildcards for a subdomain a user would want for vhost pattern matching).

Extending your initial approach a bit, let's assume for a moment subdomains for tunneling can only be one level deep (i.e. subdomain not subdomain1.subdomain2). The subdomain parameter could be moved to the beginning of the tunnel string (i.e. subdomain:project1.loc:localhost:8080) The bash script could then pattern match for the presence of a . in the first string segment (before the first : delimiter). If it contains a . we can assume it's a domain for the virtual host, if not, we can assume it's a subdomain for the ngrok tunnel.

Taking this a step further, if we wanted to support multi-level subdomains (I never actually checked if it's even possible to register multi-level subdomains in the ngrok admin panel) then we might consider adding a new delimiter (possibly the % sign). In this format we would have tunnels formatted as subdomain%project1.loc:localhost:8080 or subdomain1.subdomain2%project1.loc:localhost:8080.

TBH, I sort of like this second implementation better because it means the parsing for the standard format can remain untouched. All we would need to add is a function before it that detects the presence of the % delimiter and then strips it from the tunnel and parses it separately, leaving the remainder of the tunnel string to be parsed by the rest of the bash script.