Informer - site colaboration with JS and simple NET Core ApiController.
- 1. What is informer.
- 2. Set Up Linux machine.
- 3. Set Up and tune MySQL.
- 4. Develop NET CORE ApiController
- 5. Setup NET CORE and deploy linux-X64 assembly to server.
- 6. First start (directly in command line) and check response from ApiController.
- 7. Install remote debugger.
- 8. Tune NGINX as reverse proxy and setup SSL.
- 9. Setup CORS policy.
- 10. Demonize kestrel as Linux service.
- 11. Check finally result about informer client.
1. What is informer.
This is very simple idea to show in one site some data from other site. In this page I want to show how to do this in example with one of my oldest customer votpusk.ru. This project has two types of informers - weather and news.
As you can see, informer looks as JS packed to ASP-file, this idea generate error because IIS write JS file with wrong type, but any browser handle this issue correctly.
1: <script language="javascript" src="https://www.votpusk.ru/informer/news.asp?cn=X
2: &tm=X
3: &pc=5
4: &w=200
5: &wt=1
6: &csp=1
7: &cpd=4
8: &bg=000000
9: &bg1=E7E3E7
10: &bg2=FFFFFF
11: &ffc=0
12: &fcl=000000
13: &fcl1=000000
14: &fsz=2
15: &fsz1=3
16: &fsz2=3"></script>
This is very old my site written about 2002 year, so it was use simple ASP technology and page news.asp looks as:
As you can see this page pack some data from database and write it as JS to site-customer. For example, look to this page:
Collaboration script look as:
1:
2:
3: var xmlhttp = new XMLHttpRequest();
4: xmlhttp.open("GET", "https://informer.votpusk.ru/domain");
5: xmlhttp.setRequestHeader("Authorization", window.location.hostname);
6: xmlhttp.send();
7:
8: document.write("<font face=Arial><table width=189 cellspacing=1 bgcolor=#000000><tr><td align='center' bgcolor=#FFFFFF><table width=100%><tr><td height=20 align='center'><font size='1' color=#000000><b>НОВОСТИ ТУРИЗМА</b></font></td></tr></table><table width=95% cellspacing=0 cellpadding=2>")
9:
10: document.write("<tr><td align=center bgcolor=#E7E3E7><font size='1' color=#000000>09.11.2021</font></td></tr><tr><td valign=top bgcolor=#FFFFFF>")
11:
12: document.write("<a target='_blank' href='http://www.votpusk.ru/news.asp?msg=575748'><font size='1' color=#000000 style='font-weight:normal;'>В Индонезии планируют изменить правила въезда в страну<br><br></font></a>")
13:
14: document.write("<tr><td align=center bgcolor=#E7E3E7><font size='1' color=#000000>14.10.2021</font></td></tr><tr><td valign=top bgcolor=#FFFFFF>")
15:
16: document.write("<a target='_blank' href='http://www.votpusk.ru/news.asp?msg=575635'><font size='1' color=#000000 style='font-weight:normal;'>На остров Бали разрешили въезжать туристам из пяти стран<br><br></font></a>")
17:
18: document.write("<tr><td align=center bgcolor=#E7E3E7><font size='1' color=#000000>12.10.2021</font></td></tr><tr><td valign=top bgcolor=#FFFFFF>")
19:
20: document.write("<a target='_blank' href='http://www.votpusk.ru/news.asp?msg=575626'><font size='1' color=#000000 style='font-weight:normal;'>Индонезия сокращает период обязательного карантина по прибытии<br><br></font></a>")
21:
22: document.write("</td></tr><tr><td align=right bgcolor=#E7E3E7><a href='http://www.votpusk.ru' target='_blank'><font size='2' color=#000000>в Отпуск.ру</font></a></td></tr></table><br></td></tr></table></font>")
As you can see, this script working with dedicated domain informer.votpusk.ru what realizing on Linux NET CORE ApiController.
So below we can see full steps to up Linux NET CORE ApiController handles this request from other sites.
2. Set Up Linux machine.
In this case I use Ubuntu 20.04, than I have upgrade it to 21.01.
I will install this Ubuntu behind firewall into DMZ with IP addr 192.168.4.15 with gateway 192.168.4.1
But firstly need to select right Ubuntu distribution.
There are one potential difficulties to configure Ubuntu in this network configuration, (1) no need proxy, because firewall is full transparent, need only set a correct gateway, (2) configure bridge, (3) select right bond mode.
So, this is our finally result of network configuring of our new VM.
# cat /etc/netplan/00-installer-config.yaml
network: bonds: bond0: addresses: - 192.168.4.15/24 gateway4: 192.168.4.1 interfaces: - ens32 nameservers: addresses: - 8.8.8.8 - 8.8.4.4 search: [] parameters: mode: balance-rr ethernets: ens32: {} version: 2
Next step is first install and setup firewall and nginx.
# sudo ufw allow 33306 # sudo ufw enable # sudo ufw app list # sudo ufw port list # sudo ufw status
3. Set Up and tune MySQL.
I have a lot of version of steps to correct install MySQL, last is Setup MariaDB on Ubuntu server (remote access, user privileges, upload database), so in this server : MySQL user has been installed, Database has been created, User access has been provided, external access has been provided, firewall port for external access has been opened.
# sudo ./mariadb_repo_setup # https://mariadb.com/kb/en/mariadb/mariadb-package-repository-setup-and-usage/#platform-supporthttps://mariadb.com/kb/en/mariadb/mariadb-package-repository-setup-and-usage/#platform-support # sudo apt-get install mariadb-server mariadb-client mariadb-backup # sudo apt update # sudo apt upgrade # sudo mysql_secure_installation # sudo systemctl start mariadb # sudo systemctl enable mariadb # sudo systemctl status mariadb # mysqld --help --verbose # sudo mariadb
4. Develop NET CORE ApiController
In this case code is extremally simple. I use only 3 packages and even store connection string in code. How to store connection string more carefully please read for example in this link https://stackoverflow.com/questions/70010727/access-to-appsettings-json-in-asp-net-core-5-0-linux. Of course, header name can be any, I have selected "Authorization" only for fun.
1: using Microsoft.AspNetCore.Http;
2: using Microsoft.AspNetCore.Mvc;
3: using Microsoft.Extensions.Configuration;
4: using MySqlConnector;
5: using System;
6: using System.Collections.Generic;
7: using System.Configuration;
8: using System.Linq;
9: using System.Threading.Tasks;
10:
11: namespace Informer
12: {
13: [ApiController]
14: [Route("[controller]")]
15: public class DomainController : ControllerBase
16: {
17: private readonly MySqlConnection CN;
18: private readonly IConfiguration _config;
19: public DomainController(IConfiguration config)
20: {
21: _config = config;
22: CN = new MySqlConnection(_config.GetValue<string>("ConnectionString"));
23: }
24: [HttpGet]
25: public string Index()
26: {
27: try
28: {
29: CN.Open();
30: }
31: catch (Exception x)
32: {
33: throw new Exception(x + "\n" + CN.ConnectionString);
34: }
35:
36: if (CN.State == System.Data.ConnectionState.Open)
37: {
38: if (Request.Headers["Authorization"].Count > 0)
39: {
40: string DM = Request.Headers["Authorization"];
41: MySqlCommand CMD = new MySqlCommand($"INSERT INTO `informers`.`domain` (`crdate`,`name`) SELECT now(),'{DM}' WHERE NOT EXISTS (SELECT '1' FROM `informers`.`domain` WHERE `name`= '{DM}' )", CN);
42: CMD.ExecuteNonQuery();
43: CN.Close();
44: return "";
45: }
46: else
47: {
48: List<string> str1 = new List<string>();
49: MySqlCommand CMD1 = new MySqlCommand("SELECT * FROM informers.domain;",CN);
50: MySqlDataReader DR = CMD1.ExecuteReader();
51: while (DR.Read())
52: {
53: str1.Add(DR["name"].ToString());
54: }
55: return string.Join(",", str1);
56: }
57: }
58: else return "";
59: }
60: }
61: }
5. Setup NET CORE and deploy linux-X64 assembly to server.
# wget https://packages.microsoft.com/config/ubuntu/21.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb # sudo dpkg -i packages-microsoft-prod.deb # rm packages-microsoft-prod.deb # sudo apt-get update; sudo apt-get install -y apt-transport-https && sudo apt-get update && sudo apt-get install -y aspnetcore-runtime-5.0
6. First start (directly in command line) and check response from ApiController.
# sudo mkdir /srv/informer # chown proxyadmin /srv/informer # sudo chown proxyadmin /srv/informer # /usr/bin/dotnet /srv/informer/Informer.dll # curl -v localhost:5000/domain
Unfortunately, first start this application has been unsuccessful despite correct working in developer computer, so best way to understand issue is install Remote debugger.
7. Install remote debugger.
Unfortunately, I have no time for this project to correct fix issue with config, customer want to see finally result immediately, so my solution for 5 second was simple store connection string to controller constructor.
8. Tune NGINX as reverse proxy and setup SSL.
# sudo nano /etc/nginx/nginx.conf # sudo service nginx restart # journalctl -xe # ps -aux # kill -9 289321
1: user www-data;
2: worker_processes auto;
3: pid /run/nginx.pid;
4: include /etc/nginx/modules-enabled/*.conf;
5:
6: events {
7: worker_connections 768;
8: # multi_accept on;
9: }
10:
11: http {
12:
13: ##
14: # Basic Settings
15: ##
16:
17: sendfile on;
18: tcp_nopush on;
19: types_hash_max_size 2048;
20: # server_tokens off;
21:
22: # server_names_hash_bucket_size 64;
23: # server_name_in_redirect off;
24:
25: include /etc/nginx/mime.types;
26: default_type application/octet-stream;
27:
28: ##
29: # SSL Settings
30: ##
31:
32: ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
33: ssl_prefer_server_ciphers on;
34:
35: ##
36: # Logging Settings
37: ##
38:
39: access_log /var/log/nginx/access.log;
40: error_log /var/log/nginx/error.log;
41:
42: ##
43: # Gzip Settings
44: ##
45:
46: gzip on;
47:
48: # gzip_vary on;
49: # gzip_proxied any;
50: # gzip_comp_level 6;
51: # gzip_buffers 16 8k;
52: # gzip_http_version 1.1;
53: # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
54:
55: ##
56: # Virtual Host Configs
57: ##
58:
59: include /etc/nginx/conf.d/*.conf;
60: include /etc/nginx/sites-enabled/*;
61:
62:
63:
64: #mail {
65: # # See sample authentication script at:
66: # # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
67: #
68: # # auth_http localhost/auth.php;
69: # # pop3_capabilities "TOP" "USER";
70: # # imap_capabilities "IMAP4rev1" "UIDPLUS";
71: #
72: # server {
73: # listen localhost:110;
74: # protocol pop3;
75: # proxy on;
76: # }
77: #
78: # server {
79: # listen localhost:143;
80: # protocol imap;
81: # proxy on;
82: # }
83: #}
84:
85: server {
86: listen 80;
87: listen 443 ssl;
88: server_name informer.votpusk.ru;
89: ssl_certificate /srv/cert/cert2019.crt;
90: ssl_certificate_key /srv/cert/votpusk2019.key;
91:
92:
93: location / {
94: #root /srv/ftp;
95: #index index.html index.htm;
96: proxy_pass http://localhost:5000;
97: proxy_http_version 1.1;
98: proxy_set_header Upgrade $http_upgrade;
99: proxy_set_header Connection keep-alive;
100: proxy_set_header Host $host;
101: proxy_cache_bypass $http_upgrade;
102: proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
103: proxy_set_header X-Forwarded-Proto $scheme;
104: if ($request_method = 'GET') {
105: add_header 'Access-Control-Allow-Origin' '*';
106: add_header 'Access-Control-Allow-Credentials' 'true';
107: add_header 'Access-Control-Allow-Methods' 'GET';
108: add_header 'Access-Control-Allow-Headers' 'Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
109: }
110: }
111: }
112: }
113:
9. Setup CORS policy.
10. Demonize kestrel as Linux service.
# sudo nano /etc/systemd/system/kestrel-1.service # systemctl enable kestrel-1.service # sudo systemctl enable kestrel-1.service # sudo systemctl start kestrel-1.service # systemctl --full --type service --all
1: [Unit]
2: Description=kestrel apps daemon
3:
4: [Service]
5: WorkingDirectory=/srv/informer/
6: ExecStart=/usr/bin/dotnet /srv/informer/Informer.dll
7: Restart=always
8: RestartSec=10
9: SyslogIdentifier=Informer
10: User=root
11: Environment=ASPNETCORE_ENVIRONMENT=Development
12:
13: [Install]
14: WantedBy=multi-user.target
11. Check finally result about informer client.
Finally result looks terrible, so many hard step need to receive one ugly string. But this is correct result of this program.
|