You are viewing the documentation for Blueriq 17. Documentation for other versions is available in our documentation directory.
Blueriq has a standard Material Theme packaged but when creating your own theme this must be deployed somehow.
You need a web server for this that conforms to these requirements:
- The web server should be able to serve static content
- The web server should be able to proxy API requests to the runtime
By proxying the runtime requests, the theme and the backend share the same origin, so XHR-requests from theme to runtime are allowed by the default browser security policy.
Suitable web servers include, but are not limited to nginx, Apache httpd and IIS.
Yarn build
The Material Kickstarter comes with 2 build scripts and both use a different environment.ts file which can be configured if needed. Configurating in this case means changing the baseUrl.
- Change the `environment.runtime.ts` baseUrl to `/server`
- Run `yarn build:runtime` (which uses the environment.runtime.ts's configuration)
- When finished: Copy the content of /dist to a application server you prefer (for nginx that would be: /html)
nginx
For getting started with nginx please take a look at their documentation: https://www.nginx.com/resources/wiki/
The following configuration is the minimum needed to get the theme up and running. You could need adjustments to fit your own specific setup.
error_log logs/error.log; events { worker_connections 1024; } http { upstream revProxyRuntime { # 1: Replace <host>:<port>, example: my.runtime.local:8080 server <host>:<port>; } server { include ../conf/mime.types; listen 1337; # Instruct the browser to always verify that its cache is up-to-date add_header Cache-Control 'max-age=0, must-revalidate'; location / { root html; index index.html index.htm; try_files $uri $uri/ /index.html =404; } # 2: /server matches with what was configured in the environment.ts baseUrl location /server/ { proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host:$server_port; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Port $server_port; # 3: This uses the upstream (step 1): So this becomes: http://<host>:<port>/<context>/server/$and_the_rest_of_it; # Change the <context> part to the context root of the runtime. This is 'Runtime' if you installed Blueriq with the installer. proxy_pass http://revProxyRuntime/<context>$request_uri; proxy_cookie_path /<context> /; } } }
External Theme
When your custom theme is configured as a external theme in the Development Tools Component, you should add an additional location block for /runtime calls. Without doing so the development toolbar is unable to retrieve session information from the runtime when you start a project using the your custom theme as the external theme. More information about configuring external themes can be found here.
error_log logs/error.log; events { worker_connections 1024; } http { upstream revProxyRuntime { # 1: Replace <host>:<port>, example: my.runtime.local:8080 ... } server { include ../conf/mime.types; listen 1337; # Instruct the browser to always verify that its cache is up-to-date add_header Cache-Control 'max-age=0, must-revalidate'; location / { ... } # 2: /server matches with what was configured in the environment.ts baseUrl location /server/ { ... } # 3: /runtime matches Runtime calls which are made by the development toolbar location /runtime/ { proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host:$server_port; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Port $server_port; proxy_pass http://revProxyRuntime$request_uri; proxy_cookie_path /Runtime /; } } }
2 Comments
Mike van Emmerik
Sometimes the frontend is build with the following baseUrl `/runtime`, but `/runtime/server/` is expected. The following rewrite rule will rewrite this
`rewrite ^/runtime/(?!server)(.*)$ /runtime/server/$1 break;`
Note how it only rewrites if it did not already contain `/server`
Eelco de Lang
If the frontend is on a aws s3 bucket, you can also add a S3ReverseProxyServlet:
package nl.nn.blueriq.reverseproxy;
import java.io.IOException;
import java.io.OutputStream;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.Protocol;
import com.amazonaws.SdkClientException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.GetObjectRequest;
import com.amazonaws.services.s3.model.Region;
import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.s3.model.S3ObjectInputStream;
public class S3ReverseProxyServlet extends HttpServlet
{
private static final String REGION_ID = Region.EU_Ireland.getFirstRegionId();
protected String bucketName = "mybucket";
private AmazonS3 s3Client;
@Override
public String getServletInfo()
{
return "s3 reverse proxy";
}
@Override
public void init()
throws ServletException
{
ClientConfiguration config = new ClientConfiguration();
config.setProtocol(Protocol.HTTPS);
config.setRequestTimeout((int) TimeUnit.MINUTES.toMillis(3));
config.setSocketTimeout((int) TimeUnit.MINUTES.toMillis(3));
s3Client = AmazonS3ClientBuilder.standard().withRegion(FIRST_REGION_ID).withClientConfiguration(config).build();
}
@Override
public void destroy()
{
if (s3Client != null)
super.destroy();
}
@Override
protected void service(HttpServletRequest servletRequest, HttpServletResponse servletResponse)
throws ServletException, IOException
{
String pathInfo = servletRequest.getPathInfo();
if (pathInfo != null && pathInfo.length() > 1) {
// Remove starting slash
String filename = pathInfo.substring(1);
String mimeType = getServletContext().getMimeType(filename);
servletResponse.setContentType(mimeType);
streamS3File(servletResponse.getOutputStream(), bucketName, filename);
System.out.println("BlueriqReverseProxy handled request:" + pathInfo + " ContentType: " + mimeType);
}
else {
servletResponse.getOutputStream().println("BlueriqReverseProxy");
}
}
private void streamS3File(final OutputStream output, String bucketName, String key)
{
GetObjectRequest req = new GetObjectRequest(bucketName, key);
S3Object s3Object = s3Client.getObject(req);
S3ObjectInputStream objectContent = s3Object.getObjectContent();
try {
byte[] buffer = new byte[1024 * 10];
int bytesRead = -1;
while ((bytesRead = objectContent.read(buffer)) > -1) {
output.write(buffer, 0, bytesRead);
}
}
catch (IOException ex) {
objectContent.abort();
throw new SdkClientException("Unable to transfer content from Amazon S3 to the output stream", ex);
}
finally {
try {
objectContent.close();
}
catch (IOException ex) {
}
}
}
}