├── Dockerfile ├── apply-from-env.php └── README.md /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu 2 | MAINTAINER Christian Lück 3 | 4 | RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y \ 5 | nginx php5-cli 6 | 7 | RUN rm /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default 8 | 9 | ADD apply-from-env.php apply-from-env.php 10 | CMD ./apply-from-env.php && /usr/sbin/nginx -g "daemon off;" 11 | 12 | EXPOSE 80 13 | 14 | -------------------------------------------------------------------------------- /apply-from-env.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | $value) { 49 | if (substr($key, -5) === '_NAME') { 50 | $prefix = substr($key, 0, -5); 51 | 52 | $name = $value; 53 | $pos = strrpos($name, '/'); 54 | if ($pos !== false) { 55 | $name = substr($name, $pos + 1); 56 | } 57 | 58 | $url = getUrlFromEnv($prefix, $name); 59 | if ($url === null) { 60 | continue; 61 | } 62 | 63 | // base path (sub-folder) 64 | $path = '/'; 65 | 66 | $url = str_replace('tcp://', 'http://', $url) . $path; 67 | $servers[$name] = $url; 68 | 69 | echo '/' . $name . ' => ' . $url . PHP_EOL; 70 | } 71 | } 72 | 73 | if (!$servers) { 74 | echo 'No servers found' . PHP_EOL; 75 | exit(1); 76 | } 77 | 78 | $config = '# automatically generated by /apply-from-env.php 79 | server { 80 | listen 80; 81 | root /dev/null; 82 | 83 | '; 84 | 85 | if (($default = env('default', null)) !== null) { 86 | $config .= ' 87 | # redirect default name 88 | location = / { 89 | return 301 ' . $default . '; 90 | } 91 | '; 92 | } 93 | 94 | foreach ($servers as $name => $url) { 95 | $config .= ' 96 | 97 | # proxy for ' . $name . ' 98 | location /' . $name . '/ { 99 | proxy_pass ' . $url . '; 100 | 101 | # rewrite redirect / location headers to match this subdir 102 | proxy_redirect default; 103 | proxy_redirect / $scheme://$http_host/' . $name . '/; 104 | 105 | proxy_set_header Host $http_host; 106 | proxy_set_header X-Forwarded-For $remote_addr; 107 | } 108 | 109 | # requests without trailing slash will be forwarded to include slash 110 | location = /' . $name . ' { 111 | return 301 $scheme://$http_host$uri/$is_args$args; 112 | }'; 113 | } 114 | 115 | $config .= ' 116 | } 117 | '; 118 | 119 | file_put_contents('/etc/nginx/sites-enabled/default', $config); 120 | 121 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # docker-frontroute 2 | 3 | A docker image to automatically set up a front router (reverse proxy) for linked web containers. 4 | 5 | ## About FrontRoute 6 | 7 | [Docker](https://www.docker.io) is a great tool when it comes to setting up dedicated and isolated environments. 8 | Among others, it can be used to easily start up several web-based containers like your favorite blogging platform, 9 | a wiki and much more. 10 | 11 | Once your web-based containers are up, you may want to expose them to the outside world (the internet). 12 | Because each container comes with an own webserver, one has to expose each to a dedicated port (which tends to be *ugly*), 13 | bind to several IPs (which are not always available) or use one of the more complex options (DNS or SSL/SNI-based load balancer) etc. 14 | 15 | As an alternative, this docker image allows you to spin up a reverse proxy in front of your existing web containers. 16 | No additional configuration required, besides linking each of your existing web containers to this container. 17 | 18 | ## Usage 19 | 20 | This docker image is available as a [trusted build on the docker index](https://index.docker.io/u/clue/frontroute/), 21 | so using this image for the first time will start a download automatically. 22 | Further runs will be immediate, as the image will be cached locally. 23 | 24 | As an example, let's assume you own the domain `example.com` and you already have running several docker containers 25 | with their webservers exposed to the outside like this: 26 | 27 | ```bash 28 | $ docker run -d -p 81:80 --name ttrss clue/ttrss 29 | $ docker run -d -p 82:80 --name h5ai clue/h5ai 30 | ``` 31 | 32 | In this example, you'd have to access your different webservers like this: 33 | 34 | ``` 35 | http://example.com:81/ 36 | http://example.com:82/ 37 | ``` 38 | 39 | This certainly doesn't have a particularly good usability. 40 | Port numbers are difficult to remember and do not map well to the service actually offered. 41 | Also, available port numbers are a limited resource. 42 | 43 | Wouldn't it be nice if we could use clean URLs using sub-paths instead of ports? 44 | 45 | ``` 46 | http://example.com/ttrss/ 47 | http://example.com/h5ai/ 48 | ``` 49 | 50 | This docker image makes it trivially easy to do so. 51 | Instead of exposing each individual docker image to the outside, 52 | we can use this docker image to place a lightweight and fast reverse proxy (nginx) in front of the other images. 53 | 54 | Following the above example, we simple drop the port statements for our webserver instances like this: 55 | 56 | ```bash 57 | $ docker run -d --name ttrss clue/ttrss 58 | $ docker run -d --name h5ai clue/h5ai 59 | ``` 60 | 61 | Finally, all we have to do is start our new front router container by linking each of the webserver instances like this: 62 | 63 | ```bash 64 | $ docker run -d -p 80:80 --link ttrss:ttrss --link h5ai:h5ai clue/frontroute 65 | ``` 66 | 67 | This will start the frontrouter container in a detached session in the background. 68 | 69 | You can supply any number of linked containers. Each of them has to be given in the format `{ContainerName}:{RoutePath}`. 70 | 71 | ## Ports 72 | 73 | For each linked container, it will automatically expose its webserver port through the reverse proxy. 74 | If your container exposes several ports, it will try to use one of the common ports (80, 8080 and 8000) first and 75 | will otherwise fall back to the first available port. 76 | 77 | You can also explicitly define a custom port for each webserver by passing an environment variable like this: 78 | 79 | ``` 80 | --env h5ai_port=80 81 | ``` 82 | 83 | ## Default route 84 | 85 | Now that every sub-route is set up and running, what happens when you access the main (default) URL? 86 | 87 | ``` 88 | http://example.com/ 89 | ``` 90 | 91 | Accessing this URL will return a `404 File not found` error. 92 | 93 | You can also explicitly define a default route by passing an environment variable like this: 94 | 95 | ``` 96 | --env default=h5ai 97 | ``` 98 | 99 | Accessing this URL will now result in a `301 Moved Permanently` status code that will redirect to the `h5ai` route. 100 | 101 | ## Cleanup 102 | 103 | This container is disposable, as it doesn't store any information at all. 104 | If you don't need it anymore, you can `stop` and `remove` it. 105 | --------------------------------------------------------------------------------