Skip to content

Commit

Permalink
Merge pull request #56 from devilbox/release-1.0-beta2
Browse files Browse the repository at this point in the history
Release 1.0 beta2
  • Loading branch information
cytopia authored Dec 27, 2022
2 parents 36c416a + d59fe77 commit ba552c8
Show file tree
Hide file tree
Showing 11 changed files with 395 additions and 34 deletions.
6 changes: 3 additions & 3 deletions Dockerfiles/Dockerfile.alpine
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ LABEL \
###
### Build arguments
###
ARG VHOST_GEN_GIT_REF=1.0.8
ARG VHOST_GEN_GIT_REF=1.0.9
ARG WATCHERD_GIT_REF=v1.0.7
ARG CERT_GEN_GIT_REF=0.10

Expand All @@ -38,7 +38,7 @@ RUN set -eux \
${RUN_DEPS} \
\
# Install vhost-gen
&& wget --no-check-certificate -O vhost-gen.tar.gz "https://github.com/devilbox/vhost-gen/archive/refs/tags/${VHOST_GEN_GIT_REF}.tar.gz" \
&& wget --no-check-certificate -O vhost-gen.tar.gz "https://github.com/devilbox/vhost-gen/archive/${VHOST_GEN_GIT_REF}.tar.gz" \
&& tar xvfz vhost-gen.tar.gz \
&& cd "vhost-gen-${VHOST_GEN_GIT_REF}" \
&& make install \
Expand Down Expand Up @@ -66,7 +66,7 @@ RUN set -eux \
ENV MY_USER=nginx
ENV MY_GROUP=nginx
ENV HTTPD_START="/usr/sbin/nginx"
ENV HTTPD_RELOAD="nginx -s stop"
ENV HTTPD_RELOAD="nginx -s reload"
ENV HTTPD_VERSION="nginx -V 2>&1 | head -1 | awk '{print \$3}'"
ENV VHOSTGEN_HTTPD_SERVER="nginx"

Expand Down
6 changes: 3 additions & 3 deletions Dockerfiles/Dockerfile.debian
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ LABEL \
###
### Build arguments
###
ARG VHOST_GEN_GIT_REF=1.0.8
ARG VHOST_GEN_GIT_REF=1.0.9
ARG WATCHERD_GIT_REF=v1.0.7
ARG CERT_GEN_GIT_REF=0.10

Expand All @@ -36,7 +36,7 @@ RUN set -eux \
${RUN_DEPS} \
\
# Install vhost-gen
&& wget --no-check-certificate -O vhost-gen.tar.gz "https://github.com/devilbox/vhost-gen/archive/refs/tags/${VHOST_GEN_GIT_REF}.tar.gz" \
&& wget --no-check-certificate -O vhost-gen.tar.gz "https://github.com/devilbox/vhost-gen/archive/${VHOST_GEN_GIT_REF}.tar.gz" \
&& tar xvfz vhost-gen.tar.gz \
&& cd "vhost-gen-${VHOST_GEN_GIT_REF}" \
&& make install \
Expand Down Expand Up @@ -65,7 +65,7 @@ RUN set -eux \
ENV MY_USER=nginx
ENV MY_GROUP=nginx
ENV HTTPD_START="/usr/sbin/nginx"
ENV HTTPD_RELOAD="nginx -s stop"
ENV HTTPD_RELOAD="nginx -s reload"
ENV HTTPD_VERSION="nginx -V 2>&1 | head -1 | awk '{print \$3}'"
ENV VHOSTGEN_HTTPD_SERVER="nginx"

Expand Down
41 changes: 35 additions & 6 deletions Dockerfiles/data/docker-entrypoint.d/.httpd/func-backend.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ set -o pipefail
### conf:phpfpm:tcp:<host>:<port> # Remote PHP-FPM server at <host>:<port>
### conf:rproxy:http:<host>:<port> # Reverse Proxy server at http://<host>:<port>
### conf:rproxy:https:<host>:<port> # Reverse Proxy server at https://<host>:<port>
### conf:rproxy:ws:<host>:<port> # Reverse Proxy (websocket) at ws://<host>:<port>
### conf:rproxy:wss:<host>:<port> # Reverse Proxy (websocket) at wss://<host>:<port>
###
###
### Format-2: file:<file>
Expand All @@ -40,6 +42,8 @@ set -o pipefail
### Examples:
### conf:rproxy:http:10.0.0.1:3000
### conf:rproxy:https:mydomain.com:8080
### conf:rproxy:ws:10.0.0.1:3000
### conf:rproxy:wss:10.0.0.1:3000
###
### Note: If no file is found, a warning will be logged and no Reverse proxy will be created.
###
Expand Down Expand Up @@ -90,7 +94,13 @@ backend_conf_is_valid() {
fi
# 3. Protocol: 'tcp', 'http' or 'https'
if ! backend_is_valid_conf_prot "${1}"; then
echo "Invalid backend conf:<prot> in: '${1}'. It must be 'tcp', 'http' or 'https'"
# Apache 2.2 does not have websocket support
if [ "${VHOSTGEN_HTTPD_SERVER}" = "apache22" ]; then
echo "Invalid backend conf:<prot> in: '${1}'. It must be 'tcp', 'http' or 'https'."
# All other webserver have websocket support
else
echo "Invalid backend conf:<prot> in: '${1}'. It must be 'tcp', 'http', 'https', 'ws' or 'wss'."
fi
return 1
fi
# 4. Host
Expand All @@ -116,9 +126,22 @@ backend_conf_is_valid() {
fi
# 7. Validate conf <protocol> rproxy == http(s)?
if [ "${backend_conf_type}" = "rproxy" ]; then
if [ "${backend_conf_prot}" != "http" ] && [ "${backend_conf_prot}" != "https" ]; then
echo "Invalid backend conf:<prot> in: '${1}'. 'rproxy' only supports 'http' or 'https'"
return 1
# Apache 2.2 does not have websocket support
if [ "${VHOSTGEN_HTTPD_SERVER}" = "apache22" ]; then
if [ "${backend_conf_prot}" != "http" ] \
&& [ "${backend_conf_prot}" != "https" ]; then
echo "Invalid backend conf:<prot> in: '${1}'. 'rproxy' only supports 'http' and 'https'"
return 1
fi
# All other webserver have websocket support
else
if [ "${backend_conf_prot}" != "http" ] \
&& [ "${backend_conf_prot}" != "https" ] \
&& [ "${backend_conf_prot}" != "ws" ] \
&& [ "${backend_conf_prot}" != "wss" ]; then
echo "Invalid backend conf:<prot> in: '${1}'. 'rproxy' only supports 'http', 'https', 'ws' and 'wss'"
return 1
fi
fi
fi
}
Expand Down Expand Up @@ -181,8 +204,14 @@ backend_is_valid_conf_prot() {
local value
value="$( get_backend_conf_prot "${1}" )"

if [ "${value}" != "tcp" ] && [ "${value}" != "http" ] && [ "${value}" != "https" ]; then
return 1
if [ "${VHOSTGEN_HTTPD_SERVER}" = "apache22" ];then
if [ "${value}" != "tcp" ] && [ "${value}" != "http" ] && [ "${value}" != "https" ]; then
return 1
fi
else
if [ "${value}" != "tcp" ] && [ "${value}" != "http" ] && [ "${value}" != "https" ] && [ "${value}" != "ws" ] && [ "${value}" != "wss" ]; then
return 1
fi
fi
return 0
}
Expand Down
37 changes: 27 additions & 10 deletions Dockerfiles/data/docker-entrypoint.d/02-env-vars-validate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,12 @@ _validate_vhost_backend() {
# 5. Validate conf <protocol>
if ! backend_is_valid_conf_prot "${value}"; then
_log_env_valid "invalid" "${name}" "${value}" "Invalid format"
_log_env_valid "invalid" "${name}" "${backend_conf_prot}" "<proto> is invalid. Must be: " "'tcp', 'http' or 'https'"
# Apache 2.2 does not have websocket support
if [ "${VHOSTGEN_HTTPD_SERVER}" = "apache22" ];then
_log_env_valid "invalid" "${name}" "${backend_conf_prot}" "<proto> is invalid. Must be: " "'tcp', 'http' or 'https'"
else
_log_env_valid "invalid" "${name}" "${backend_conf_prot}" "<proto> is invalid. Must be: " "'tcp', 'http', 'https', 'ws' or 'wss'"
fi
_log_backend_examples "conf"
exit 1
fi
Expand All @@ -662,11 +667,21 @@ _validate_vhost_backend() {
fi
# 7. Validate conf <protocol> rproxy == http(s)?
if [ "${backend_conf_type}" = "rproxy" ]; then
if [ "${backend_conf_prot}" != "http" ] && [ "${backend_conf_prot}" != "https" ]; then
_log_env_valid "invalid" "${name}" "${value}" "Invalid format"
_log_env_valid "invalid" "${name}" "${backend_conf_prot}" "rproxy only supports protocol " "'http' or 'https'"
_log_backend_examples "conf"
exit 1
# Apache 2.2 does not have websocket support
if [ "${VHOSTGEN_HTTPD_SERVER}" = "apache22" ];then
if [ "${backend_conf_prot}" != "http" ] && [ "${backend_conf_prot}" != "https" ]; then
_log_env_valid "invalid" "${name}" "${value}" "Invalid format"
_log_env_valid "invalid" "${name}" "${backend_conf_prot}" "rproxy only supports protocol " "'http' and 'https'"
_log_backend_examples "conf"
exit 1
fi
else
if [ "${backend_conf_prot}" != "http" ] && [ "${backend_conf_prot}" != "https" ] && [ "${backend_conf_prot}" != "ws" ] && [ "${backend_conf_prot}" != "wss" ]; then
_log_env_valid "invalid" "${name}" "${value}" "Invalid format"
_log_env_valid "invalid" "${name}" "${backend_conf_prot}" "rproxy only supports protocol " "'http', 'https', 'ws' and 'wss'"
_log_backend_examples "conf"
exit 1
fi
fi
fi
# 8. Validate conf <host>
Expand Down Expand Up @@ -1062,11 +1077,13 @@ _log_backend_examples() {
log "err" "Example: conf:phpfpm:tcp:10.0.0.100:9000"
log "err" "Example: conf:phpfpm:tcp:domain.com:9000"
log "err" ""
log "err" "Example: conf:rproxy:http:10.0.0.100:3000"
log "err" "Example: conf:rproxy:http:domain.com:443"
log "err" ""
log "err" "Example: conf:rproxy:https:10.0.0.100:8080"
log "err" "Example: conf:rproxy:http:10.0.0.100:8080"
log "err" "Example: conf:rproxy:https:domain.com:8443"
if [ "${VHOSTGEN_HTTPD_SERVER}" != "apache22" ]; then
log "err" ""
log "err" "Example: conf:rproxy:ws:10.0.0.100:8080"
log "err" "Example: conf:rproxy:wss:domain.com:8443"
fi
fi
if [ "${show}" = "all" ] || [ "${show}" = "file" ]; then
log "err" ""
Expand Down
2 changes: 1 addition & 1 deletion Dockerfiles/data/nginx/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ http {

# [emerg] could not build server_names_hash, you should increase server_names_hash_bucket_size: 32
# https://stackoverflow.com/questions/26357487/
server_names_hash_bucket_size 64;
server_names_hash_bucket_size 128;


# -------------------------------------------------------------------------------
Expand Down
27 changes: 23 additions & 4 deletions Dockerfiles/data/vhost-gen/templates-main/nginx.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,31 @@ vhost_type:
root "__DOCUMENT_ROOT__";
index __INDEX__;
# Reverse Proxy (-r)
# Reverse Proxy (-r http(s)://ADDR:PORT)
rproxy: |
# Define the vhost to reverse proxy
# Define Reverse Proxy
location __LOCATION__ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# https://stackoverflow.com/a/72586833
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Proxy connection
proxy_pass __PROXY_PROTO__://__PROXY_ADDR__:__PROXY_PORT__;
}
# Reverse Proxy with websocket support (-r ws(s)://ADDR:PORT)
rproxy_ws: |
# Define Reverse Proxy with Websock support
location __LOCATION__ {
# https://stackoverflow.com/a/72586833
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Websocket settings
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
# Proxy connection
proxy_pass __PROXY_PROTO__://__PROXY_ADDR__:__PROXY_PORT__;
}
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

This image is based on the official **[Nginx](https://hub.docker.com/_/nginx)** Docker image and extends it with the ability to have **virtual hosts created automatically**, as well as **adding SSL certificates** when creating new directories. For that to work, it integrates two tools that will take care about the whole process: **[watcherd](https://github.com/devilbox/watcherd)** and **[vhost-gen](https://github.com/devilbox/vhost-gen)**.

From a users perspective, you mount your local project directory into the container under `/shared/httpd`. Any directory then created in your local project directory wil spawn a new virtual host by the same name. Each virtual host optionally supports a generic or custom backend configuration (**static files**, **PHP-FPM** or **reverse proxy**).
From a users perspective, you mount your local project directory into the container under `/shared/httpd`. Any directory then created in your local project directory wil spawn a new virtual host by the same name. Each virtual host optionally supports a generic or custom backend configuration: **static files**, **PHP-FPM**, **reverse proxy** (with or without **websocket** support)..

**HTTP/2 is enabled by default for all SSL connections.**

Expand Down Expand Up @@ -100,7 +100,7 @@ Below is a brief overview about most outstanding features, but I would still adv
* PHP is not included in the provided images, but you can enable a remote backend and link it to a PHP-FPM image. This allows you to easily switch PHP versions and choose one which is currently required.

#### Automated Reverse Proxy setup
* In reverse proxy mode, you can choose any http or https backend of your likings. This way you can proxy NodeJS, Python, etc. and use the webserver to add SSL in front.
* In reverse proxy mode, you can choose any http or https backend of your likings. This way you can proxy NodeJS, Python, etc. and use the webserver to add SSL in front. It distinguishes between HTTP backends (`http://`, `https://`) and Websocket backends (`ws://`, `wss://`) automatically and configures accordingly.

#### Automated SSL certificate generation
* SSL certificates are generated automatically for each virtual host if you choose to enable it
Expand Down Expand Up @@ -246,6 +246,7 @@ The given examples distinguish between two different kinds of setup: The default
&nbsp;&nbsp;&nbsp;💡 <a href="doc/examples.md#-serve-php-files-with-php-fpm-and-sync-local-permissions" >Sync local filestem permission</a><br/>
&nbsp;&nbsp;&nbsp;💡 <a href="doc/examples.md#-serve-php-files-with-php-fpm-over-https" >Serve PHP files over HTTPS</a><br/>
&nbsp;&nbsp;&nbsp;💡 <a href="doc/examples.md#-act-as-a-reverse-proxy-for-nodejs" >Reverse Proxy NodeJS</a><br/>
&nbsp;&nbsp;&nbsp;💡 <a href="doc/examples.md#-act-as-a-reverse-proxy-websockets" >Reverse Proxy Websocket</a><br/>
</td>
<td>
<strong>Unlimited vhosts</strong><br/>
Expand Down
6 changes: 4 additions & 2 deletions doc/environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ The given value determines the backend (potentia remote/reveres hosts) for the m
* **Var type:** `string`
* **Requires:** `MAIN_VHOST_ENABLE=1`
You can configure a remote backend via this environment variable. Either a remote PHP-FPM server or any kind of service via `http` or `https` reverse proxy.
You can configure a remote backend via this environment variable. Either a remote PHP-FPM server or any kind of service via `http`, `https`, `ws`, or `wss` reverse proxy (where `ws` and `wss` are for websocket backends).
### String format
Expand All @@ -369,7 +369,7 @@ The backend environment variable supports two different formats.
With the direct configuration you set everything explicitly via this environment variable and nothing else is required.
* **`<type>`**: `phpfpm` or `rproxy`
* **`<protocol>`**: `tcp`, `http` or `https`
* **`<protocol>`**: `tcp`, `http`, `https`, `ws` or `wss`
* **`<host>`**: the address of upstream host to send requests to (`hostname`, `IPv4` or `IPv6`).
* **`<port>`**: the port of the upstream host to send requests to
Expand All @@ -378,6 +378,8 @@ With the direct configuration you set everything explicitly via this environment
MAIN_VHOST_BACKEND=conf:phpfpm:tcp:10.0.0.1:9000
MAIN_VHOST_BACKEND=conf:rproxy:http:10.0.0.1:3000
MAIN_VHOST_BACKEND=conf:rproxy:https:10.0.0.1:3000
MAIN_VHOST_BACKEND=conf:rproxy:ws:10.0.0.1:3000
MAIN_VHOST_BACKEND=conf:rproxy:wss:10.0.0.1:3000
```
When specifying `phpfpm`, the vhost will also automatically be configured for serving PHP files. (including `index.php` for its directory index).
Expand Down
88 changes: 86 additions & 2 deletions doc/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
3. [Serve PHP files with PHP-FPM and sync local permissions](#-serve-php-files-with-php-fpm-and-sync-local-permissions)
4. [Serve PHP files with PHP-FPM over HTTPS](#-serve-php-files-with-php-fpm-over-https)
5. [Act as a Reverse Proxy for NodeJS](#-act-as-a-reverse-proxy-for-nodejs)
6. [Fully functional LEMP stack with Mass vhosts](#-fully-functional-lemp-stack-with-mass-vhosts)
7. [Docker Compose](#-docker-compose)
6. [Act as a Reverse Proxy for Websocket](#-act-as-a-reverse-proxy-for-websocket)
7. [Fully functional LEMP stack with Mass vhosts](#-fully-functional-lemp-stack-with-mass-vhosts)
8. [Docker Compose](#-docker-compose)



Expand Down Expand Up @@ -237,6 +238,89 @@ The following example proxies all HTTP requests to a NodeJS remote backend. You
## 💡 Act as a Reverse Proxy for Websocket
The following example proxies all HTTP requests to a Websocket remote backend. You could also enable SSL on the webserver in order to access the websocket backend via HTTPS.
* **Vhost:** main (default)
* **Backend:** Reverse Proxy (with websocket support)
> 🛈 No files need to be mounted into the webserver, as content is coming from the websocket server.
1. Create a websocket server application
```bash
# Create source directory
mkdir -p src
# websocket server application
cat << EOF > src/index.js
const WebSocket = require("ws");
const wss = new WebSocket.Server({ port: 3000 });
wss.on("connection", (ws) => {
ws.send("hello client, you are connected to me");
ws.on("message", (message) => {
console.log("New message from client: %s", message);
});
});
console.log("WebSocket server ready at localhost:3000");
EOF
# package.json
cat << EOF > src/package.json
{
"name": "node-websocket-example",
"version": "1.0.0",
"main": "index.js",
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"ws": "^7.5.1"
}
}
EOF
# Startup script
cat << EOF > src/start.sh
#!/bin/sh
npm install
node index.js
EOF
```
2. Start the Websocket server container
```bash
docker run -d -it \
--name websocket \
-v $(pwd)/src:/app \
-w /app \
node:19-alpine sh start.sh
```
3. Start Reverse Proxy
```bash
docker run -d -it \
-p 80:80 \
-e MAIN_VHOST_BACKEND='conf:rproxy:ws:websocket:3000' \
--link websocket \
devilbox/nginx-stable
```
4. Verify
```bash
# On your host system
npm install -g wscat
wscat --connect localhost
Connected (press CTRL+C to quit)
< hello client, you are connected to me
>
```
## 💡 Fully functional LEMP stack with Mass vhosts
The following example creates a dynamic setup. Each time you create a new project directory below `www/`, a new virtual host is being created.
Expand Down
4 changes: 3 additions & 1 deletion doc/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,9 @@ Reverse Proxies are configured in a similar way to how PHP-FPM is setup as a rem
```bash
MAIN_VHOST_BACKEND:conf:rproxy:<protocol>:<server-addr>:<server-port>
```
Where `<procotol>` can by one of `http` or `https` (depending what your backend provides. `<server-addr>` and `<serer-port>` specify the hostname, IPv4 or IPv6 address of your upstream server, followed by its TCP port.
Where `<procotol>` can by one of `http`, `https`, `ws` or `wss` (depending what your backend provides. `<server-addr>` and `<serer-port>` specify the hostname, IPv4 or IPv6 address of your upstream server, followed by its TCP port.

**Note:** When specifying `ws` or `wss`, the webserver will automatically be configured to be capable of communicating with web sockets.



Expand Down
Loading

0 comments on commit ba552c8

Please sign in to comment.