This shows you how to configure nginx running within a docker container to proxy subdomains to random external host:ports OR to ports listening on the docker host outside of the nginx container.
Proxying connections to ports on the docker host is useful because this allows you to do things like give your customer a link like http://rails.mydomain.org/retailer/123/customers.html to view your latest website change. However, since your webapp is running on your development laptop which is not directly accessible because you work in an office behind a firewall, you need to make use of the nginx proxy to facilitate the connection.
In simple terms, this allows you to have a computer at your house that is always ON be able to make available services running on your laptop behind a firewall at some other location.
In more detailed terms, you have the following network topology components:
-
Dynamic DNS provider
This service will be dynamcially associating a domain (like: mydomain.org) with your house's external IP. You may want to configure a wildcard subdomain so that all URLs (like: http://rails.mydomain.org or http://laptop.mydomain.org) will resolve to your house's external IP.
-
Computer at home
This computer is behind a regular NAT router (like wifi) at your house. You will need to configure your NAT router to forward ports 22 and 80 to your computer. This computer will be running nginx in a docker container.
-
Development Laptop at work
This laptop is behind a firewall and is hosting a service (like a rails app) that needs to be accessed externally via an URL like http://rail.mydomain.org.
This configuration will depend on your dynamic DNS service. Basically, you want to add some domains to your domain provider which then points them to your dynamic DNS provider which then points them to your house's external IP.
-
Configure your home's router to forward ports 22 and 80 to your computer.
-
Clone this repo to your computer.
-
Install Docker on your computer if you don't already have it.
-
Configure ssh on your computer to allow non-localhost connections to be forwards through reverse ssh tunnels.
-
Add/Change the GatewayPorts config in the
/private/etc/ssh/sshd_configfile to appear as follows:GatewayPorts yes
You will need to use
sudo vi /private/etc/ssh/sshd_configto edit the file since it is owned by root. -
Restart sshd
If using linux:
$ sudo service sshd restart
If using MacOS:
$ sudo launchctl stop com.openssh.sshd
-
-
Configure a permanent static IP to be associated with your computer's loopback address. This will allow the docker container where nginx is running to access your computer regardless of arbitrary IP changes assigned by your router's DHCP.
Note that it is easy to alias an IP address to your loopback via:
$ sudo ifconfig lo0 alias 192.168.111.111However, this assignment will disappear after your next reboot. In order to make this change permanent, we will actually just be setting up a launchd daemon to run this command upon every reboot of your laptop. Note that you will need sudo permissions in order to perform this step (if you don't run with admin privileges). If you just setup your Mac with default user that was created when you first got your laptop then you will by default have admin privileges. But, since many advanced users who might be following these instructions will have created a non-privileged user for their regular account, I've added a couple steps here to show you how to temporarily add then remove yourself from the list of sudoers - thus, temporarily granting yourself sudo (root) permissions.
-
If you don't run with admin privileges then perform the following steps to grant yourself sudo access:
-
Switch to your admin account, enter your admin password then launch visudo:
$ su admin Password: ***** $ sudo visudo Password: *****
This will open the sudoers file in the 'vi' editor. Do not attempt to edit the sudoers file in any other way.
-
Add your regular account username below the root and %admin group entries like the following (except use your regular username instead of 'danlynn'):
# root and users in group wheel can run anything on any machine as any user root ALL = (ALL) ALL %admin ALL = (ALL) ALL danlynn ALL = (ALL) ALLThese lines are usually found near the bottom of the file. After adding that last line, simply save the changes and exit back to the command line.
-
-
Create a shell script to execute the IP alias command from the previous section:
-
Create a
.logindirectory in your home directory$ cd ~ $ mkdir .login $ cd .login $ touch alias_loopback.sh $ open .
-
That last command should open a Finder window displaying the new file. Open that file in your favorite editor, add the following, then save it:
#!/bin/sh ifconfig lo0 alias 192.168.111.111
-
-
Create a launchd daemon plist file to execute the
alias_loopback.shfile upon startup of your laptop:-
Create the
alias_loopback.plistdaemon plist file and set its ownership and permissions$ cd /Library/LaunchDaemons/ $ sudo touch alias_loopback.plist Password: ***** $ sudo chown root:wheel alias_loopback.plist $ sudo chmod 755 alias_loopback.plist
Note that you will only have to enter your regular user permissions on the first use of sudo. The elevated sudo permissions will stay in effect for about 5 minutes before being rescinded.
-
Open the
alias_loopback.plistfile in your favorite editor (which allows you to authenticate as admin to save changes - like sublime) -
Modify the contents of the
alias_loopback.plistfile as follows:<plist version="1.0"> <dict> <key>Label</key> <string>alias_loopback</string> <key>RunAtLoad</key> <true /> <key>Program</key> <string>/Users/danlynn/.login/alias_loopback.sh</string> </dict> </plist>
-
In theory launchd should see when the file is saved and pick up and run it. However, if it doesn't then try the following:
$ sudo launchctl load /Library/LaunchDaemons/alias_loopback.plist
-
Test that the launch control daemon is working by restarting your laptop and then pinging the new static IP alias:
$ ping 192.168.111.111 PING 192.168.111.111 (192.168.111.111): 56 data bytes 64 bytes from 192.168.111.111: icmp_seq=0 ttl=64 time=0.053 ms 64 bytes from 192.168.111.111: icmp_seq=1 ttl=64 time=0.045 ms 64 bytes from 192.168.111.111: icmp_seq=2 ttl=64 time=0.050 ms 64 bytes from 192.168.111.111: icmp_seq=3 ttl=64 time=0.034 ms
If you get timeout messages instead of results like this then try going back over these instructions and figuring out what you missed. It might be useful to tail the system log for launchd messages in this case:
$ sudo tail -f /var/log/system.log
Also, you can stop and restart the daemon without a reboot with:
$ sudo launchctl unload /Library/LaunchDaemons/alias_loopback.plist $ sudo launchctl load /Library/LaunchDaemons/alias_loopback.plist
-
-
Remove yourself from the sudoers file (if you don't run with admin privileges)
-
Edit the sudoers file:
sudo visudo Password: ***** -
Remove your regular username from the list of users with sudo privileges so that it only contains the original root and admin entries like:
# root and users in group wheel can run anything on any machine as any user root ALL = (ALL) ALL %admin ALL = (ALL) ALL
-
-
-
Customize the
config/servers/confnginx config file to match the subdomain that you want to redirect to your laptop. This file is located in this config directory in this project. The example servers.conf file is setup to forward requests forhttp://rails.mydomain.org/to port 3000 on the static loopback IP that we setup for your computerhttp://192.168.111.111:3000:upstream rails { server 192.168.111.111:3000; } server { listen 80; server_name rails.mydomain.org; location / { proxy_pass http://rails/; proxy_set_header Host $host; } }The "upstream" server defines the destination host named "rails". The
proxy_passstatement specifies that the requests should be proxied to the upstream host named "rails".The
serversection specifies that requests arriving on port 80 to theserver_name"rails.mydomain.org" will be processed.The
location /specifies that any path following the root will be carried over to the proxied upstream host URL. Thus, "http://rails.mydomain.org/" => "http://192.168.111.111:3000/" and "http://rails.mydomain.org/users/5.html" => "http://192.168.111.111:3000/users/5.html".You may add additional
upstreamandserverentries into this file to create additional proxies.This file is shared with nginx when the docker container is started. So, if you make changes, you will need to restart the docker container via:
$ docker-compose restart
-
Start the nginx docker container:
$ docker-compose start
You can display the logs with:
$ docker-compose logs
If you want to tail the logs then add an
-foption on the end of that command.The
docker-compose.ymlspecifies that this 'web' service should always be launched upon a restart of the computer. Therefore, you won't need to worry about restarting the nginx container if you need to restart your computer for an OS update or whatever.Note that any http requests sent to this computer using a hostname that is not being proxied will simply be handled directly by nginx. It is configured to host any content found in the
htmldirectory of this project.
-
Start a service ON YOUR LAPTOP which you want to be proxied by the computer at your house. For example, I'll be running a rails app on port 3000.
-
Open a reverse ssh tunnel from your laptop to the computer at your house. Execute the following ON YOUR LAPTOP:
$ ssh user@home.mydomain.org -R 0.0.0.0:3000:127.0.0.1:3000
This command specifies that any computer (0.0.0.0) which attempts to connect to port 3000 on the computer at your house will have their connection tunneled back to your laptop to hit the rails server running on port 3000 (the second 3000 number). We could have just as easily specified that it should connect to a tomcat server running locally on port 8080, etc. The "127.0.0.1" refers to your laptop's loopback IP. This is the same as "localhost". However, in certain situations, "127.0.0.1" will work where "localhost" won't. I use the IP just to be safe.