I've made a simple app in Blazor Server, and it works fine for the most part except for when I attempt to run it on my VPS with HTTPS. When I run the app no errors appear, and the websocket appears to connect successfully (viewed from the Firefox console), and yet I cannot interact with any of the components on the website. The websocket doesn't send over any anything when attempting to interact with the components either, but it keeps heartbeating.
I've made a brand new Blazor Server project and followed the following guide: https://learn.microsoft.com/en-us/aspnet/core/blazor/host-and-deploy/server, but to no avail.
The VPS runs on Ubuntu 22.04.1 LTS, Apache2 as the webserver (attemped using nginx, didn't help), and Cloudflare as the CA.
The certificate and key are correct and not outdated.
I'm running this virtual host (taken from the link above, and additionally from https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-apache?view=aspnetcore-6.0 (tried just using the configuration from the first link, didn't work)).
<VirtualHost *:*>
RequestHeader set "X-Forwarded-Proto" expr=%{REQUEST_SCHEME}
</VirtualHost>
<VirtualHost *:443>
ServerName <serverName>
Protocols h2 http/1.1
ProxyRequests On
ProxyPreserveHost On
ProxyPassMatch ^/_blazor/(.*) http://localhost:5000/_blazor/$1
ProxyPass /_blazor ws://localhost:5000/_blazor
ProxyPass / http://localhost:5000/
ProxyPassReverse / http://localhost:5000/
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
SSLEngine on
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLHonorCipherOrder off
SSLCompression off
SSLSessionTickets on
SSLUseStapling off
SSLCertificateFile /home/cf.pem
SSLCertificateKeyFile /home/cf.key
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:>
</VirtualHost>
This is how the Blazor Server main looks like (the snippet that's commented out I've tried, didn't help):
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
//builder.WebHost.ConfigureKestrel(options =>
//{
// options.ConfigureHttpsDefaults(options =>
// {
// var pem = File.ReadAllText(builder.Configuration["PemPath"]).Trim();
// var key = File.ReadAllText(builder.Configuration["KeyPath"]).Trim();
// var crt = X509Certificate2.CreateFromPem(pem, key);
// options.ServerCertificate = crt;
// });
//});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseForwardedHeaders(new() { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto });
app.UseAuthentication();
app.UseHsts();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.Run();
}
To confirm: I'm able to access the website via HTTPS, the HTTPS connection is successful, no Razor component I interact with does anything.
Any help or tips on how to proceed would be greatly appreciated, thank you!
I've solved the issue.
If anyone else comes by this having a similar issue, check with your CA (Cloudflare in my case) a setting called "auto-minify" (or similar) which minimizes your HTML, CSS, and Java.
The article that helped me solve my issue: https://zimmergren.net/solved-asp-net-core-blazor-web-sites-does-not-work-with-cloudflare-html-minification/
Related
I'm currently running a .Net Core application with SignalR on an Ubuntu Apache web server. This .Net Core app is reachable by the example.com/api path.
I also have a Vue JS app running on the webserver as well. When I attempt to establish a websocket connection to the the SignalR application, the following error occurs:
WebSocket connection to 'wss://example.com/api/mainHub?id=V3XZrhdsQDTTMIZvQ-8cbQ' failed: Error during WebSocket handshake: Unexpected response code: 200
Error: Failed to start the transport 'WebSockets': null
The Apache config for the .Net Core app is as follows:
#Main/Desired Path - https://example.com
<VirtualHost *:443>
DocumentRoot /var/www/example.com/dist/spa
ServerName example.com
#SSL Certs
SSLEngine on
SSLProtocol all -SSLv2
SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:!RC4+RSA:+HIGH:+MEDIUM:!LOW:!RC4
SSLCertificateFile /etc/apache2/ssl/example.crt
SSLCertificateKeyFile /etc/apache2/ssl/server.key
SSLCertificateChainFile /etc/apache2/ssl/example.ca-bundle
#Upgrade Websockets
RewriteEngine on
RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
RewriteRule /(.*) ws://localhost:5000/$1 [P]
#Other specific directories
ProxyPreserveHost On
ProxyPass "/api" http://localhost:5000
ProxyPassReverse "/api" http://localhost:5000
</VirtualHost>
I've added the RewriteEngine to upgrade the websockets, I'm not sure if the issue is with the configuration on Apache, or in the .Net Core app itself.
The .Net Core app has the following in the startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options => options.AddPolicy("CorsPolicy", builder =>
{
builder
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
.WithOrigins("*");
}));
services.AddSignalR();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//first handle any websocket requests
app.UseWebSockets();
app.UseCors("CorsPolicy");
app.UseSignalR(routes =>
{
routes.MapHub<mainHub>("/mainHub");
routes.MapHub<accounthub>("/accountHub");
});
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World!");
});
}
It seems that either something is incorrect in the startup.cs that is sending a 200 response back to the client when establishing the websocket connection or the Apache virtual host is not properly upgrading the websocket.
I have found this on a site ( http://shyammakwana.me/server/websockets-with-apache-reverse-proxy-with-ssl.html ) which seems to work also for me.
The apache config for the given site should be like this
<IfModule mod_ssl.c>
<VirtualHost *:443>
RewriteEngine On
ProxyPreserveHost On
ProxyRequests Off
# allow for upgrading to websockets
RewriteEngine On
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule /(.*) ws://localhost:5000/$1 [P,L]
RewriteCond %{HTTP:Upgrade} !=websocket [NC]
RewriteRule /(.*) http://localhost:5000/$1 [P,L]
ProxyPass "/" "http://localhost:5000/"
ProxyPassReverse "/" "http://localhost:5000/"
ProxyPass "/chatHub" "ws://localhost:5000/chatHub"
ProxyPassReverse "/chatHub" "ws://localhost:5000/chatHub"
ServerName site.com
SSLCertificateFile /etc/letsencrypt/live/site.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/site.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>
Also you should have these modules enabled:
a2enmod proxy
a2enmod proxy_wstunnel
I am also getting this error while deploying a ASP.NET Core 3.1 Blazor Server-side app to an Ubuntu 18.04 server running Apache2.
In combination with this error, I am also getting a 404 error trying to access static resources (.css files, images and scripts) from the Linux server, but everything works perfectly in an IIS environment. I've also noted that the contents of the WWWRoot folder in my solution do not appear to be copied to the linux server when I publish the app. I am using the FolderProfile method of publishing, then copying the contents of the publish folder to the linux server via SFTP.
The only "real" change from the boilerplate startup.Configure class (from the New Blazor-Server Web App template in VS2019) I have made is to add the UseForwardHeaders directive as described at https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-apache?view=aspnetcore-3.1
I've also added Authentication and Authorisation to the app, but once again, the whole thing runs perfectly on IIS, but it needs to be installed on a production linux server once testing is complete.
My Startup.Configure looks like:
public static void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
// Enable SyncFusion Community Edition License
Syncfusion.Licensing.SyncfusionLicenseProvider
.RegisterLicense("Key-Removed");
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
// Use Authentication and Authorisation providers in the application
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
Also, on the linux side, the virtual host configuration file looks like this:
#<VirtualHost *:*>
# RequestHeader set "X-Forwarded-Proto" expr=%{REQUEST_SCHEME}
#</VirtualHost>
<VirtualHost *:80>
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:5000/
ProxyPassReverse / http://127.0.0.1:5000/
ServerName www.grafton.internal
ErrorLog ${APACHE_LOG_DIR}labapp_error.log
CustomLog ${APACHE_LOG_DIR}labapp_access.log common
</VirtualHost>
Note I have commented out the top 3 lines because I could not get this expression to work correctly - Apache failed to start with every variation of the 2nd line I tried. I believe this might be related to my problem, but I am not sure what to do about it.
I also want to stress that this app is for internal use only, and the web server is only visible on our Intranet - there are no external / internet facing servers or sites and access is limited to a very few people via physical access to the servers, and restricted fixed IP addresses, so I am not at all concerned with using SSL.
Any assistance with this one would be appreciated. I've been trying to get this running for a week, and only have a week left before it MUST be in the linux test environment.
I am trying to host a simple Hello World on Ubuntu 16.04.5 LTS.
So far I have built the .NetCore application as a Self Contained Deployment release and ftp'd to my server inside /var/www/CoreWebsite
I have configured an existing Apache configuration inside /etc/apache2/sites-enabled/mySite with the following:
<VirtualHost *:80>
ServerName www.myWebSite.co.uk
ServerAlias myWebsite.co.uk
DocumentRoot /var/www/CoreWebsite
ProxyPass / http://localhost:4000
ProxyPassReverse / http://localhost:4000
#Other directives here
# Options -Indexes
</VirtualHost>
Inside my Program.cs I have the following:
public static void Main(string[] args)
{
var host = CreateWebHostBuilder(args)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseUrls("http://*:4000")
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
host.Run();
}
I have restarted the Apache Service and all I am getting when i navigate to myWebsite.co.uk is a 503 Service unavailable. I am not sure if I have to enable something for kesteral to be running, or enable a pass through?
This is a fresh installation and I haven't activated, or installed anything other than copying the files to the server...
I have a Docker container with wordpress:latest in a host which has Apache 2.4 installed.
I added the lines below to my Apache configuration file, inside the vhost group:
ProxyPass http://localhost:8010
ProxyPassReverse http://localhost:8010
When I try to access my URL I can reach wordpress homepage, however all static files point to localhost so my layout doesn't work.
What am I missing? Some setup at Apache? Wordpress itself?
Apache modules are already enabled.
Edit 1:
Forgot to mention: this piece of configuration is inside a Location directive, which is inside a vhost directive.
<VirtualHost *:80>
...
<Location /usa>
RequestHeader set X-Is-Reverse=Proxy true
RequestHeader set X-Original-Host mysite.com.br
ProxyPass http://localhost:8010
ProxyPreserveHost On
ProxyPassReverse http://localhost:8010
</Location>
...
</VirtualHost>
Check that the Site URL setting in wordpress matches the URL your clients are calling.
This is the documentation on how to change the site URL in wordpress: https://codex.wordpress.org/Changing_The_Site_URL
If you proxy pass to your backend like that, requests coming into your container will be sent with the Host header set to localhost. Apparently, the WordPress container takes care of the host that has been set in order to generate static assets links. Try setting the following proxy option:
ProxyPreserveHost On
Just after the ProxyPass configuration line.
This options forward the Host HTTP header coming from the client over to the proxy connection. This way the backend will understand which public URL it's been called from and asset links should be correct.
Edit.
If you can't use the ProxyPreserveHost Directive you could try and directly set the Host header using:
RequestHeader set Host "your.host.name"
I have a web app developed in VisualAge Smalltalk that uses the ABTWSAC (Web Connect) to do CGI Handling.
In Apache, I simply AddHandler cgi-script .exe in mime module and Options -Indexes FollowSymLinks ExecCGI in Directory module.
(There is also a ISAPI handler that works in IIS).
How on earth do you do this in nginx? Nginx seems to always want a running service on a port or a 'unix' socket (which is clearly not support on windows).
All the googling shows that people assume cgi in nginx must be PHP. None of the examples or explinations tell me how to do what I want to do specifically.
As far as I know Nginx does not have native CGI support. It supports "only" fastCGI.
In my eyes you have four options:
1) Change from ABTWSAC (Web Connect) to seaside. Then use seaside with VisualAge Smalltalk. I would go with this guide
Copied from the link for later reference:
Our Bare Bones Nginx FastCGI Configuration
worker_processes 1;
events
{
worker_connections 1024;
}
http
{
include mime.types;
default_type application/octet-stream;
upstream seaside
{
server localhost:9001;
server localhost:9002;
server localhost:9003;
}
server
{
root /var/www/glass/;
location /
{
error_page 403 404 = #seaside;
}
location #seaside
{
include fastcgi_params;
fastcgi_pass seaside;
}
}
}
2) Reverse proxy to Seaside (again requiring switching from ABTWSAC (Web Connect)), for more see this link
3) Install Apache or lighthttpd, different port than ngnix, on the same server. You want to proxy cgi-bin folder via nginx. I know it kind of beats the purpose for having nginx only, but it is also a possible solution so I'm writing it here.
You can write to your nginx (running on 8888 port) configuration:
location /cgi-bin {
proxy_pass http://127.0.0.1:8888
}
4) As you already suggested running web server with native CGI support like your mentioned apache or lighthttpd.
Dusty,
If I remember correctly, you can also use Web Connect on Top of SST, which basically is just an in-image HTTP server.
So your Web server (nginx) only needs to act as an HTTP (Reverse) Proxy. It is not faster than fastCGI but requires only minimal changes to your Web Connect setup process in the image startup procedure...
I deployed my first meteor app on a digital-ocean droplet using mup. So it's there but I can't figure out what I still have to setup to actually view my app. So when I go to www.example.com I should see it but all I see is an apache page.
When you start a Meteor app, you can specify the port for it to listen on using the --port argument. For it to be available from at you domain name specify port 80. Though if you have Apache listening on that port already it will fail to bind to it. Uninstall or stop Apache, and restart your Meteor app.
If you are using Apache to serve other content and can not stop it, you'll need to have your Meteor run on a different port with an Apache ProxyPass. First enable mod_proxy and mod_proxy_http
sudo a2enmod proxy proxy_http
Then create a new VirtualHost for the Meteor app that proxies request to the port you have decided to have it listen on. It will look something like:
<VirtualHost *:80>
ServerName www.example.com
ProxyPass / http://localhost:3000/
ProxyPassReverse / http://localhost:3000/
ServerAdmin webmaster#localhost
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
See this article for all the details.