Local testing
Assuming that your application runs locally at port 3000 you can easily use following Dockerfile examples to test the auth handler locally.
note
In examples below we generate self-signed certificates which shouldn't be used in production. For local testing this shouldn't be a problem.
You can either test locally with nginx or httpd container. In both cases you will need to build image from provided Dockerfile. Both images have the same build argument list which can be seen below:
auth_handler_url- the URL for auth handler; default:none- must be providedlocal_domain- where is your application running locally; default: app.localhostlocal_host_ip- your local machine IP address; default: host.docker.internallocal_host_port- your local machine port; default: 3000c- certificate country; default: USst- certificate state; default: Statel- certificate locality; default: Localityo- certificate organisation; default: ACMEou- certificate organisation unit; default: ACME unitcn- certificate common name; default: value fromlocal_domainemail_address- certificate email address; default: no-reply@app.localhost
tip
If host.docker.internal does not work for you try to replace it with real url obtained by following command:
# macOS
ipconfig getifaddr en0
# linux
hostname -I
tip
Do not forget to add following record to your /etc/hosts file:
127.0.0.1 app.localhost
Proxy with Nginx
Create file Dockerfile with following content:
FROM alpine as builder
# Local domain
ARG local_domain=app.localhost
ENV env_local_domain=$local_domain
# Country
ARG c=US
ENV env_c=$c
# State or province
ARG st=State
ENV env_st=$st
# Locality
ARG l=Locality
ENV env_l=$l
# Organisation
ARG o=ACME
ENV env_o=$o
# Organisation Unit
ARG ou="ACME unit"
ENV env_ou=$ou
# Common name
ARG cn=$env_local_domain
ENV env_cn=$cn
# Email address
ARG email_address=no-reply@app.localhost
ENV env_email_address=$email_address
WORKDIR /opt
RUN apk add openssl
RUN openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout server.key -out server.crt -subj "/C=$env_c/ST=$env_st/L=$env_l/O=$env_o/OU=$env_ou/CN=$env_cn/emailAddress=$env_email_address"
FROM nginx:alpine as proxy
# Local host IP
ARG local_host_ip=host.docker.internal
ENV env_local_host_ip=$local_host_ip
# Local host port
ARG local_host_port=3000
ENV env_local_host_port=$local_host_port
# Auth handler URL
ARG auth_handler_url
ENV env_auth_handler_url=$auth_handler_url
# Local domain
ARG local_domain=app.localhost
ENV env_local_domain=$local_domain
# copy certificate
COPY --from=builder /opt/server.key /etc/nginx/ssl/server.key
COPY --from=builder /opt/server.crt /etc/nginx/ssl/server.crt
# build virtualhost file
RUN echo -e '\
server {\n\
listen 443 ssl;\n\
server_name {localdomain};\n\
resolver 8.8.8.8;\n\
\n\
ssl_certificate /etc/nginx/ssl/server.crt;\n\
ssl_certificate_key /etc/nginx/ssl/server.key;\n\
\n\
location / {\n\
proxy_pass http://{localhostip}:{localhostport}$request_uri;\n\
proxy_set_header Host $proxy_host;\n\
\n\
proxy_redirect off;\n\
proxy_http_version 1.1;\n\
proxy_set_header Upgrade $http_upgrade;\n\
proxy_set_header Connection "upgrade";\n\
proxy_read_timeout 600s;\n\
\n\
# Preserve original headers, cookies, and query strings\n\
proxy_pass_request_headers on;\n\
proxy_pass_request_body on;\n\
}\n\
\n\
location /auth {\n\
proxy_pass https://{authhandlerurl}$request_uri;\n\
# proxy_set_header Host $http_host;\n\
proxy_set_header Host $proxy_host;\n\
proxy_set_header X-Forwarded-Host $host;\n\
\n\
# proxy_redirect off;\n\
proxy_http_version 1.1;\n\
proxy_set_header Upgrade $http_upgrade;\n\
proxy_set_header Connection "upgrade";\n\
proxy_read_timeout 600s;\n\
\n\
# Preserve original headers, cookies, and query strings\n\
proxy_pass_request_headers on;\n\
proxy_pass_request_body on;\n\
}\n\
}'\
> /etc/nginx/conf.d/proxy.conf
# Perform environment variable substitution using sed
RUN sed -i \
-e "s|{localdomain}|$env_local_domain|g" \
-e "s|{authhandlerurl}|$env_auth_handler_url|g" \
-e "s|{localhostip}|$env_local_host_ip|g" \
-e "s|{localhostport}|$env_local_host_port|g" \
/etc/nginx/conf.d/proxy.conf
EXPOSE 443
Build the container from the Dockerfile (see the available build args list in previous section):
docker build -t citadel/nginx:latest . --build-arg auth_handler_url={authHandlerUrl}
note
Do not forget to replace {authHandlerUrl} with the real URL - URL shouldn't contain https:// nor the trailing slash
Run the proxy by following command:
docker run --dns 8.8.8.8 -it -p 443:443 citadel/nginx:latest
After the docker container is running you can navigate to https://app.localhost.
Proxy with Apache2
Create file Dockerfile with following content:
FROM alpine as builder
# Local domain
ARG local_domain=app.localhost
ENV env_local_domain=$local_domain
# Country
ARG c=US
ENV env_c=$c
# State or province
ARG st=State
ENV env_st=$st
# Locality
ARG l=Locality
ENV env_l=$l
# Organisation
ARG o=ACME
ENV env_o=$o
# Organisation Unit
ARG ou="ACME unit"
ENV env_ou=$ou
# Common name
ARG cn=$env_local_domain
ENV env_cn=$cn
# Email address
ARG email_address=no-reply@app.localhost
ENV env_email_address=$email_address
WORKDIR /opt
RUN apk add openssl
RUN openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout server.key -out server.crt -subj "/C=$env_c/ST=$env_st/L=$env_l/O=$env_o/OU=$env_ou/CN=$env_cn/emailAddress=$env_email_address"
FROM httpd:alpine as proxy
# Local host IP
ARG local_host_ip=host.docker.internal
ENV env_local_host_ip=$local_host_ip
# Local host port
ARG local_host_port=3000
ENV env_local_host_port=$local_host_port
# Auth handler URL
ARG auth_handler_url
ENV env_auth_handler_url=$auth_handler_url
# Local domain
ARG local_domain=app.localhost
ENV env_local_domain=$local_domain
# copy certificate
COPY --from=builder /opt/server.key /usr/local/apache2/conf/server.key
COPY --from=builder /opt/server.crt /usr/local/apache2/conf/server.crt
# enable neccessary modules
RUN sed -i \
-e 's/^#\(LoadModule .*mod_socache_shmcb.so\)/\1/' \
-e 's/^#\(LoadModule .*mod_proxy.so\)/\1/' \
-e 's/^#\(LoadModule .*mod_proxy_http.so\)/\1/' \
-e 's/^#\(LoadModule .*mod_ssl.so\)/\1/' \
-e 's/^#\(LoadModule .*mod_rewrite.so\)/\1/' \
-e 's/^#\(Include .*httpd-default.conf\)/\1/' \
-e 's/^#\(Include .*httpd-ssl.conf\)/\1/' \
conf/httpd.conf
# build virtualhost file
RUN echo -e '\
<VirtualHost *:443>\n\
ServerName {localdomain}\n\
\n\
SSLEngine on\n\
SSLCertificateFile /usr/local/apache2/conf/server.crt\n\
SSLCertificateKeyFile /usr/local/apache2/conf/server.key\n\
\n\
# Disable SSL certificate verification\n\
SSLProxyEngine On\n\
SSLProxyVerify none\n\
SSLProxyCheckPeerCN off\n\
SSLProxyCheckPeerName off\n\
\n\
ProxyPreserveHost On\n\
\n\
# Proxy requests to /auth to https://{authhandlerurl}/\n\
<Location "/auth">\n\
ProxyPass "https://{authhandlerurl}/"\n\
ProxyPassReverse "https://{authhandlerurl}/"\n\
\n\
# Forward necessary headers\n\
RequestHeader set X-Forwarded-Host "{localdomain}"\n\
RequestHeader set X-Forwarded-Proto "https"\n\
RequestHeader setifempty Sec-Fetch-Mode "%{Sec-Fetch-Mode}e"\n\
RequestHeader setifempty Sec-Fetch-Site "%{Sec-Fetch-Site}e"\n\
RequestHeader setifempty Sec-Fetch-Dest "%{Sec-Fetch-Dest}e"\n\
RequestHeader setifempty Sec-Fetch-User "%{Sec-Fetch-User}e"\n\
RequestHeader setifempty Referer "%{Referer}i"\n\
\n\
RequestHeader set Host "{authhandlerurl}"\n\
\n\
</Location>\n\
\n\
# Proxy all other requests to http://{localhostip}:{localhostport}/\n\
ProxyPass "/" "http://{localhostip}:{localhostport}/"\n\
ProxyPassReverse "/" "http://{localhostip}:{localhostport}/"\n\
\n\
# Forward headers for all other requests\n\
RequestHeader set X-Forwarded-Host "{localdomain}"\n\
RequestHeader set X-Forwarded-Proto "https"\n\
\n\
</VirtualHost>'\
> conf/extra/httpd-default.conf
# Perform environment variable substitution using sed
RUN sed -i \
-e "s|{localdomain}|$env_local_domain|g" \
-e "s|{authhandlerurl}|$env_auth_handler_url|g" \
-e "s|{localhostip}|$env_local_host_ip|g" \
-e "s|{localhostport}|$env_local_host_port|g" \
conf/extra/httpd-default.conf
EXPOSE 443
Build the container from the Dockerfile (see the available build args list in previous section):
docker build -t citadel/httpd:latest . --build-arg auth_handler_url={authHandlerUrl}
note
Do not forget to replace {authHandlerUrl} with the real URL - URL shouldn't contain https:// nor the trailing slash
Run the proxy by following command:
docker run --dns 8.8.8.8 -it -p 443:443 citadel/httpd:latest
After the docker container is running you can navigate to https://app.localhost.