FPWebModule add HTTPS support lazarus / 38-Networking and Web Programming ---------------------------------------------------------------------- TheMouseAUS · 2021-04-27 01:49 Hi, I have written many small apps in Delphi 2007 with Indy10 over the past years, I am self taught and always read examples on how to do things. I needed to be more up-to date with 64bit and thought Lazarus would be a good fit. I have written an application using 'HTTP Server Application' which created FPWebModule. Took me a while to figure things out which is very hard when most of the documentation dates back to 2006 and even the examples in the source folder seem out of date. Anyway I have it all working and I am very happy with the end result. Except to host on the web I now have to switch to HTTPS and I cannot find any simple example on how to do this or if its even possible,  otherwise I will have migrate the whole app using Indy 10 instead which isn't ideal. Older posts say no its not possible, newer ones suggest support is added. I am a bit lost. Sorry I am a newbie. ---------------------------------------------------------------------- Handoko · 2021-04-27 04:23 Hello TheMouseAUS, Welcome to the forum. Web and network programming is not my expertise. But I remember there were some issues when accessing secure sites one or two years ago. I heard that issue has been solved in most recent version of Lazarus/FPC. ---------------------------------------------------------------------- trev · 2021-04-27 05:46 There's a Free Pascal HTTPS web server example for FPC 3.0.4, 3.2.0 and 3.3.1 (trunk) included at: /usr/local/share/fpcsrc/fpc- 3.x.x/packages/libmicrohttpd/examples/https_fileserver_example.pp in the FPC distribution. It uses libmicrohttpd rather than fpWeb. There is also an example of an HTTPS web server in the Wiki Light Web Server which uses  Synapse and Free Pascal. ---------------------------------------------------------------------- TheMouseAUS · 2021-04-27 06:14 I have manged to create a secure socket on port 443. I added application.useSSL := True and added openSSLsockets, openSSL to uses. It is trying to work but I cannot figure out how to get openSSL to load both the cert and key I generated. I have tried all sorts and keep coming up short. I am trying not to have to change the whole project just to add this otherwise I will just switch to Indy10 which will work. ---------------------------------------------------------------------- xinyiman · 2021-04-27 07:11 I go by heart so I could be wrong. I seem to remember that certificate management is handled by openssl. So based on your architecture (windows, linux or mac) you have to figure out the directory where openssl goes to fetch the certificates. And then you generate them with the openssl tools. ---------------------------------------------------------------------- TheMouseAUS · 2021-04-27 07:12 OK I have tried SSLCTXusecertificatefile(SSLCTXnew(SslMethodV23), 'c:\temp\cert.pem', SSL_FILETYPE_PEM) SSLCTXusePrivateKeyfile(SSLCTXnew(SslMethodV23), 'c:\temp\key.pem', SSL_FILETYPE_PEM) It is returning as OK but still have no certs when I try and load webpage ---------------------------------------------------------------------- MvC · 2021-04-27 11:27 Hi, If you're using a released version of FPC/Lazarus, then setting a certificate requires creating a descendent of THTTPServerHandler and overriding CreateServer. Function TMyHTTPServerHandler.CreateServer : THTTPServer: begin   Result:=Inherited CreateServer;   //  Configure certificate   Result.CertificateData.Certificate.FileName:='yourcertificate.pem';   Result.CertificateData.PrivateKey.FileName:='yourprivatekey.pem'; end; Then, create a descendent of THTTPApplication. Override InitializeWebHandler to return your class: function TMyHTTPApplication.InitializeWebHandler: TWebHandler; override; begin   Result:=TMyHTTPServerHandler.Create(Self); end; That's it. If you use Trunk FPC, then as of rev. 49276, you can simply configure it in your project file: Application.HTTPhandler.CertificateData.Certificate.FileName:='yourcer tificate.pem'; Application.HTTPhandler.CertificateData.PrivateKey.FileName:='yourpriv atekey.pem'; ---------------------------------------------------------------------- TheMouseAUS · 2021-04-27 12:32 Awesome thanks MVC, please just a little more help so I understand,  were in the following project would it go? There no point posting all my project so I created a quick one with all the relevant bits. QuoteFunction TMyHTTPServerHandler.CreateServer : THTTPServer: begin   Result:=Inherited CreateServer;   //  Configure certificate   Result.CertificateData.Certificate.FileName:='yourcertificate.pem';   Result.CertificateData.PrivateKey.FileName:='yourprivatekey.pem'; end; Then, create a descendent of THTTPApplication. Override InitializeWebHandler to return your class: function TMyHTTPApplication.InitializeWebHandler: TWebHandler; override; begin   Result:=TMyHTTPServerHandler.Create(Self); end; Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+} interface uses  SysUtils, Classes, httpdefs, fpHTTP, fpWeb , opensslsockets, openssl; type   { TFPWebModule1 }   TFPWebModule1 = class(TFPWebModule)    procedure DataModuleRequest(Sender: TObject; ARequest: TRequest;      AResponse: TResponse; var Handled: Boolean);  private   public   end; var  FPWebModule1: TFPWebModule1; implementation {$R *.frm} { TFPWebModule1 } procedure TFPWebModule1.DataModuleRequest(Sender: TObject; ARequest: TRequest;  AResponse: TResponse; var Handled: Boolean);begin  With AResponse.Contents do   Begin    Add('');    Add('');    Add('');    Add('       ');    Add('       ');    Add('       ');    Add('       TimeSheet');    Add('');    Add('');    Add('
');    Add('');    Add('  

Welcome Nathan
');    Add('';    end; end; initialization  RegisterHTTPModule('TFPWebModule1', TFPWebModule1);end.  Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program httpproject1; {$mode objfpc}{$H+} uses  fphttpapp, unit1; begin  Application.Title:='httpproject1';  Application.UseSSL := true;  Application.Port:=443;  Application.Threaded:=True;  Application.LegacyRouting := True;  Application.Initialize;  Application.Run;end. ---------------------------------------------------------------------- PascalDragon · 2021-04-28 07:09 Quote from: TheMouseAUS on April 27, 2021, 02:32:53 pmAwesome thanks MVC, please just a little more help so I understand,  were in the following project would it go? There no point posting all my project so I created a quick one with all the relevant bits. Either the main project file or (better) a separate unit. It might be best to copy the contents of FpHttpApp and adjust that. You then need to use your new unit instead of FpHttpApp. ---------------------------------------------------------------------- Warfley · 2021-04-28 16:03 I recommend putting your FPWeb server behind a reverse proxy. Besides making using HTTPs with LetsEncrypt easy as a walk in the park, this has several other advantages, first you can manage multiple different web applications on the same port (e.g. on different domains or paths) with little configuration effort, which would be a massive undertaking to implement yourself in pascal. Second you can manage asset files (e.g. images) and access rights (htaccess) completely from within your webserver, requiring only a few lines of config, which you otherwise would need to handle in your code which clutters your core webapp. Also software like nginx is very well tested and by having this as your "front line" you minimize the attack surface for potential attackers. Besides this the fpWeb does afaik not support HTTP/2, which nginx does. HTTP/2 has a lot of advantages in transmittion (mostly being better compressed and more efficient), so by using a reverse proxy that uses HTTP/2 to the clients and then translates the requests to HTTP/1.1 (or 1.0) for the fpWeb backend, you can increase efficency and decrease loading times for the user. Lastly this works really well in combination with docker, which I can only whole heartedly recommend as this massively eases server software management  and further reduce the possible attack surface. This also makes developing and debugging much easier, you develop it locally using HTTP and don't care about anything else, then when you want to deploy, you simply docker it up and run the container on your server and the reverse proxy manages all the SSL stuff. For nginx you simply need to add the following config file to your nginx: Code: Text  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i server {  server_name [URL];    ssl on;    listen 443 ssl http2;    listen [::]:443 ssl http2;    client_max_body_size 5G;    ssl_certificate /etc/letsencrypt/live/[URL]/fullchain.pem; # managed by Certbot    ssl_certificate_key /etc/letsencrypt/live/[URL]/privkey.pem; # managed by Certbot    root [ROOTPATH];    access_log [LOGPATH];    error_log [LOGPATH];    location ~ /.well-known/acme-challenge/ {        allow all;    }    location ~ /assets/ {        allow all;    }    location / {        proxy_set_header Host $http_host;        proxy_pass http://localhost:[LOCALPORT];    }    index index.php index.html index.htm;} server {    ssl on;    server_name www.[URL];    listen 443 ssl http2;    listen [::]:443 ssl http2;    allow all;    ssl_certificate /etc/letsencrypt/live/[URL]/fullchain.pem; # managed by Certbot    ssl_certificate_key /etc/letsencrypt/live/[URL]/privkey.pem; # managed by Certbot    return 301 http://[URL]$request_uri;} where you have to replace [URL] with the hostname you want to be reachable (e.g. example.com), [ROOTPATH] with the path to the file root of that server (in which the assets folder is located), [LOGPATH] with the path to the log file and [LOCALPORT] with the locally available port your fpweb application is running on. This configuration grants direct access to files in the acme-challange and assets folder, the acme-challange folder is required for the letsencrypt certbot (to get your certificate) and the assets folder can be used to place images and stuff in that should be directly loaded and will not be passed through to your application. I use this template now since like 2016 or so and every time I create a new webapp I simply copy it, change these fields and run lets encrypt. ---------------------------------------------------------------------- xinyiman · 2021-04-28 16:31 I am attaching a working example (tested on linux and mac). I have installed (today) the trunk version of both lazarus and fpc (with the fpcupdeluxe tool). Once this is done, unpack the attachment, in pkg you will find the source to open. Compile it, go to ../bin and before launching the executable create the two necessary files with the following command openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout privateKey.key -out certificate.crt If then the command differs for windows I don't know, on mac and linux it works fine. This should be all. Let me know. ---------------------------------------------------------------------- PierceNg · 2021-04-29 02:36 Quote from: Warfley on April 28, 2021, 06:03:09 pmI recommend putting your FPWeb server behind a reverse proxy. Lastly this works really well in combination with docker +1 on using a HTTPS reverse proxy, really simplifies the development. Makes it easy to try out other web frameworks like Brook. Also +1 for Docker. FPC-produced executables work on Alpine Linux, a lightweight security-oriented Linux distro widely used in Docker container images. I posted this https://wiki.freepascal.org/Docker_Containerization wiki page few months back. ---------------------------------------------------------------------- PascalDragon · 2021-04-29 07:27 Quote from: Warfley on April 28, 2021, 06:03:09 pmBesides this the fpWeb does afaik not support HTTP/2, which nginx does. HTTP/2 has a lot of advantages in transmittion (mostly being better compressed and more efficient), so by using a reverse proxy that uses HTTP/2 to the clients and then translates the requests to HTTP/1.1 (or 1.0) for the fpWeb backend, you can increase efficency and decrease loading times for the user. fpWeb as of right now does not, but there is this. And MvC hopes to integrate that with fpWeb. Though of course there are still enough reasons to use a reverse proxy. ---------------------------------------------------------------------- cappe · 2021-04-29 07:46 Quote from: xinyiman on April 28, 2021, 06:31:27 pmI am attaching a working example (tested on linux and mac). I have installed (today) the trunk version of both lazarus and fpc (with the fpcupdeluxe tool). Once this is done, unpack the attachment, in pkg you will find the source to open. Compile it, go to ../bin and before launching the executable create the two necessary files with the following command openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout privateKey.key -out certificate.crt If then the command differs for windows I don't know, on mac and linux it works fine. This should be all. Let me know. Thanks ---------------------------------------------------------------------- Warfley · 2021-04-29 13:47 Quote from: PascalDragon on April 29, 2021, 09:27:30 amfpWeb as of right now does not, but there is this. And MvC hopes to integrate that with fpWeb. Thats great, also with a reverse proxy this allows for utilizing the full features of HTTP/2 through the reverse proxy. ---------------------------------------------------------------------- TheMouseAUS · 2021-04-30 20:24 Thanks everyone, I did look into using a reverse proxy but there may be times its not needed but I do see its advantages. I was hoping to get some definitive examples on how to implement HTTPS using FP-web so its well documented because currently its currently lacking a bit. Quote from: xinyiman on April 28, 2021, 06:31:27 pmI am attaching a working example (tested on linux and mac). I have installed (today) the trunk version of both lazarus and fpc (with the fpcupdeluxe tool). Once this is done, unpack the attachment, in pkg you will find the source to open. Compile it, go to ../bin and before launching the executable create the two necessary files with the following command openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout privateKey.key -out certificate.crt If then the command differs for windows I don't know, on mac and linux it works fine. This should be all. Let me know. Thanks for your example, I did try that but for some reason i didnt work for me but I will give it a go again.