תהליך העלאת מערכת fullstack מה-localhost לעולם האמיתי
-
מתעד את נסיונותי להפעיל SSL תקין באמצעות Kestrel. (אולי יעזור למישהו בעתיד)
הוספתי ב-launchSetting.json את הרשומה הבאה:"sslProd": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": false, "launchUrl": "swagger", "applicationUrl": "https://localhost:443", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Production" } }
dotnet publish +winsp
ועדיין כשאני מנסה לפנות באמצעות פורט 443 יש שגיאה:ubuntu@vps-c2df8674:~$ curl -I http://localhost:443/api/Numbers/GetNumbersFromDotnet curl: (7) Failed to connect to localhost port 443: Connection refused
ניסיתי עוד כמה פתרונות כמו זה
וכן שינוי משתנה הסביבהASPNETCORE_ENVIRONMENT
ל-sslProd או production, ושום דבר לא עוזר. ה-ssl מסרב לתקשר. אני מתיאש לע"ע מהכיוון הזה ואנסה לחבר את ה-nginx בתור רוורס פרוקסי (למדתי מה זה), ואולי הוא ידע להעיר מהתרדמת את תקשורת ה-ssl. -
@yyy כל ההגדרות שתעשה עד מחר לא ייתנו לך בחיים SSL,
SSL מקבלים על ידי חברה חיצונית שהיא גורם מוסמך והתעודה העליונה שלהן מכובדת ע"י הקליינטים.
ואני לא מבין למה אתה כה מתעקש ללכת בדרכים משלך במקום לעשות בתום מה שמדריכים אותך.
מה דחוף עכשיו SSL? למה אתה לא מגדיר את הNGINX כמו במדריך הרשמי של מקרוסופט? -
אם מהתחלה הייתי מרגיש שאתה "הולך אחרי" היית אחרי כל הסיפור הזה תוך יום אחד.
מתחיל הנושא אני מרגיש שאני מדבר עם מישהו ששואל אבל חושש/חשדן/ממש כל תשובה ומה שנקרא מנסה "להבין לבד".
יש בזה משהו חיובי אבל תבין שאין פה באמת דיון בריא, כשכותרת הנושא היא מה התהליך ובפועל זה בעצם בואו תעזרו לי להסתדר לבד. -
@yyy SSL אומר שהתעודה מוצפנת בפרוטוקול מסוים עם מה שנקרא תעודות, שמעידות שהתשובה שהדפדפן מקבל אכן מגיעה מהשרת של הדומיין tchumim.com ולא נפתחה/עברה טיפול בדרך.
אלא שכל אחד יכול להנפיק תעודה בשם כל דומיין שירצה, ולכן כמו שכתב @dovid חברה חיצונית (CA) מאשרת שהתעודה שלך תקפה, והוא אחראי בין השאר לוודא לפני הנפקת התעודה שאכן הדומיין מצביע על השרת, כלומר שהשרת מורשה לייצג את הדומיין, וככה אני לא יכול לייצר תעודה עבור tchumim.com, לשבת באמצע התעבורה, לחטט בה ולהצפין מחדש עם התעודה שלי, כיוון שהתעודה שלי לא מאושרת על ידי CA.לאור כל הנ"ל, לא אמור להיות לך SSL לכתובת שהיא localhost כלומר פנימית בשרת, ולכן גם אין כזה דבר https://localhost (מלבד תעודה בהנפקה עצמית לצורך פיתוח שלא רלוונטית לכאן).
התעודה נצרכת לצורך ניתוב החוצה ורק כאשר יש דומיין, הדרך הנפוצה היא להאזין בפורט רגיל, 80 או 3000 וכו', ולהשתמש במה שנקרא reverse-proxy כגון nginx/caddy, שיש לו כאן 2 מטרות:- לנתב את כל הבקשות שמגיעות לשרת בפורט 443 לפורט הפנימי 3000 - של האפליקציה עצמה (רק במידה והאפליקציה לא מאזינה ישירות בפורט 443)
- לדאוג לחלק של הHTTPS, כלומר לקחת את התשובה של השרת דוטנט שלך שמגיעה בלי הצפנה כמובן בפורט פנימי, ולעטוף אותה בפרוטוקול ההצפנה והתעודות שיבטיחו לדפדפן של הגולש שהתוכן מקורי ושלם
ישנן דרכים נוספות, כמו להאזין ישירות בפורט 443 עם האפליקציה ולתת לה לנהל את עניין הSSL בעצמה (סעיף 2) - שזה אולי מה שניסית אבל לא מקובל ומיותר, או להשתמש בSSL של Cloudflare - שזה בעצם ממש reverse-proxy כמו האחרים, רק שהוא קורא בשרת של קלאודפלייר במקום בשרת שלך.
כדאי לקרוא https://www.digicert.com/what-is-an-ssl-certificate
-
@dovid
קיבלתי. מעכשיו אני זורם איתך.
אני כעת מבצע את מה שכתוב כאן.
כעת יש לי תקשורת באמצעות הדפדפן המוגדרת ע"י קובץ ה-/etc/nginx/sites-available/default
הזה:server { listen 80; server_name 62.88.198.72; location / { proxy_pass http://127.0.0.1:5000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection keep-alive; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }
השאלה כעת היא
איך משלבים את ההגדרות של האנגולר דלעיל באותו קובץ(?)? -
אז תשנה בהתאם את הקובץ הdefault:
server { listen 80; server_name 62.88.198.72; location /api { proxy_pass http://127.0.0.1:5000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection keep-alive; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location / { root /var/www/html; try_files $uri $uri/ /index.html; index index.html; } }
-
בשל המעבר לדוטנט 7 אני נתקל בשגיאת CORS עקשנית. עד היום בדוטנט 3 אם הייתי רוצה לאפשר פניות מכיוון הלקוח הייתי מגדיר כך:
app.UseCors(x => x .AllowAnyMethod() .AllowAnyHeader() .SetIsOriginAllowed(origin => true) // allow any origin
בדוטנט 7 ע"פ מייקרוסופט הדרך אמורה להיות כך:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins"; var builder = WebApplication.CreateBuilder(args); builder.Services.AddCors(options => { var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy"; options.AddPolicy(name: MyAllowSpecificOrigins, policy => { policy.WithOrigins("http://localhost:4200") .SetIsOriginAllowedToAllowWildcardSubdomains(); }); }); ... app.UseCors(MyAllowSpecificOrigins); app.UseAuthorization();
וזה כדי לאשר לכה"פ לדפדפן עם אנגולר על localhost לגשת לשרת.
ע"פ המוצע כאן ניסיתי לשנות לזה:
builder.Services.AddCors(options => { options.AddPolicy(myAllowSpecificOrigins, policy => { policy.WithOrigins("https://localhost:4200", "http://localhost:4200"); policy.WithHeaders("*"); }); });
לא עזר.
בנוסף ניסיתי להוסיף בקונטרולר את שורת הקודה הבאהHttpContext.Response.Headers.Add("Access-Control-Allow-Origin", "http://localhost:4200");
לא עזר.
כך נראה האנגולר שקורא לדוטנט :
getNumberFromDb(): Observable<number> { let httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json;charset=utf-8', Authorization: "", }), }; return this.httpClient.get<number>(this.getNumberFromDbURL, httpOptions); }
איך אפשר לאפשר לכל דפדפן לפנות לדוטנט בלי לקבל את השגיאה הנ"ל?
המון תודה!עריכה מאוחרת : הפיתרון הוא
- למחוק את ה-headers מהאנגולר
- למחוק את המידלוור
app.UseHttpsRedirection();
-
@yyy הדרך הנכונה היא מה שכתבתי לך לעיל
@dovid כתב בתהליך העלאת מערכת fullstack מה-localhost לעולם האמיתי:
(יש לי חשד שבאנגולר אתה פונה לlocalhost:5000. זה טעות נפוצה אצל מפתחי אנגולר שהם לא מודעים כלל ליום שאחרי הפיתוח.
זה כמובן לא יעבוד, הרי הlocalhost לא יילך איתך למחשבי הגולשים.
מה שצריך לעשות תמיד זה או לפנות באנגולר לאותו דומיין (ע"י כתובת יחסית שמתחילה בלוכסן) או לדומיין אחר גם בעת הפיתוח.
איך זה יעבוד? הרי בזמן הפיתוח אתה עובד מול localhost? בשביל זה מגדירים בהגדרות הserve פרוקסי שאומר שכל כתובת שמתחילה בapi או כל כלל אחר, אנא נתב אותה נכון לשעת הפיתוח לlocalhost:5000).אני יודע שאתה תוהה מה הקשר בין לזה לCORS, אבל זה לא רק הפתרון אלא ככה היית אמור לעשות רק שלא היה לך מורה טוב.
-
@dovid אני בהחלט מבין את הקשר ל-CORS, (ולא מעט בזכות זה) אבל רק לגבי הפתרון של לפנות לאנגולר באותו דומיין שהוא בתורו יפנה לשרת.
הפתרון של פניה ישירה לשרת גם בזמן הפיתוח לכאורה עדיין יגרום ל-CORS הלא כן?אני כעת עובד בהתאם לשיטה השניה וכאמור בגלל המעבר לדוטנט 7 אני צריך לפתוח מעט את הקוד ולהכיר סינטקסים שונים.
בכ"א תודה.
-
@yyy כתב בתהליך העלאת מערכת fullstack מה-localhost לעולם האמיתי:
(ולא מעט בזכות זה)
תודה.
הפתרון של פניה ישירה לשרת גם בזמן הפיתוח לכאורה עדיין יגרום ל-CORS הלא כן?
לזה התכוונתי שלא תבין כי זה אכן לא מובן במבט ראשון.
התשובה היא שהפרוקסי מבוצע ע"י התהליך של הserve שפשוט לא מחוייב לחוקי הcors. -
@yyy כתב בתהליך העלאת מערכת fullstack מה-localhost לעולם האמיתי:
אני מניח שבדומה להפניות ל-Localhost, גם כאן כבר בשלב הפיתוח צריך לשנות את ה-ConnectionString שיהיה מקושר לשרת, אמת?
אני כנראה לא הובנתי,
האנגולר רץ במחשב הגולש. שמה הlocalhost הוא קשקוש, הרי לא רץ שמה צד שרת במחשב שלו!
הדוטנט רץ בשרת וכך גם הSQL, כך שאין פסול תמיד להצביע על שרת נוכחי = localhost.
(כמו"כ בדוטנט יש קובץ הגדרות נפרד לדריסה עבור הפרודקשיין, כך שזה לא בעיה לנהל שני מחרוזות חיבור).
אגב בקונקשיין סטרינג מציינים שרת נוכחי ע"י נקודה, למשל . או .\sqlexpress, כמו"כ בwindows הרבה פעמים מתחברים לsqlserver באותו מחשב עם אישורי windows כלומר בלי סיסמה, בלינוקס נדרשים להתחבר עם שם משתמש וסיסמה לזכרוני. -
@dovid את זה הבנתי. מה שהתכוונתי להשוות ל-Localhost שזו נקודה שדורשת התייחסות כבר בשלב הפיתוח בגלל שיתכן שמדובר בשני מחרוזות שונות
אני מימשתי את זה בינתיים כך ב-appsettings.json
:"ConnectionStrings": { "UploadProject": "Data Source=(localdb)\\ProjectsV13;Initial Catalog=UploadProject;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False", "DeployedProject": "Server=localhost;Database=UploadProject;User Id=SA;Password=mypass@;" },
כאשר המחרוזת השניה היא בפורמט לינוקס.
וב-program.cs
הקוד ככה:if (builder.Environment.IsDevelopment()) { builder.Services.AddDbContext<Context>(options => options .UseSqlServer(builder.Configuration .GetConnectionString("UploadProject"))); } else { builder.Services.AddDbContext<Context>(options => options .UseSqlServer(builder.Configuration .GetConnectionString("DeployedProject"))); }
העניין שכשאני מנסה לגשת ל-SQL דרך הקונטרולר הרלוונטי אני מקבל שגיאה הבאה: (מעתיק לע"ע רק את התוכן שנראה לי רלוונטי, כי השגיאה אורכה כאורך הגלות (אם יהיה צורך אני יעלה את כולה))
ubuntu@vps-c2df8674:/var/www/publish$ curl http://localhost/api/Numbers/GetNumberFromDb fail: Microsoft.EntityFrameworkCore.Database.Connection[20004] An error occurred using the connection to database 'UploadProject' on server 'localhost'. fail: Microsoft.EntityFrameworkCore.Query[10100] An exception occurred while iterating over the results of a query for context type 'upload7API.Data.Context'. Microsoft.Data.SqlClient.SqlException (0x80131904): A connection was successfully established with the server, but then an error occurred during the pre-login handshake. (provider: TCP Provider, error: 35 - An internal exception was caught) ---> System.Security.Authentication.AuthenticationException: The remote certificate was rejected by the provided RemoteCertificateValidationCallback. at System.Net.Security.SslStream.SendAuthResetSignal(ProtocolToken message, ExceptionDispatchInfo exception) at System.Net.Security.SslStream.CompleteHandshake(SslAuthenticationOptions sslAuthenticationOptions) at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](Boolean receiveFirst, Byte[] reAuthenticationData, CancellationToken cancellationToken) at System.Net.Security.SslStream.AuthenticateAsClient(SslClientAuthenticationOptions sslClientAuthenticationOptions) at Microsoft.Data.SqlClient.SNI.SNITCPHandle.EnableSsl(UInt32 options) at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at Microsoft.Data.SqlClient.TdsParser.EnableSsl(UInt32 info, SqlConnectionEncryptOption encrypt, Boolean integratedSecurity) at Microsoft.Data.SqlClient.TdsParser.ConsumePreLoginHandshake(SqlConnectionEncryptOption encrypt, Boolean trustServerCert, Boolean integratedSecurity, Boolean& marsCapable, Boolean& fedAuthRequired, Boolean tlsFirst)
ממה שקצת חפרתי מדובר בנושא שקשור ל-SSL (אני כבר פוחד להזכיר את המושג הזה (-:).
יש עוד נקודה שאשמח לדעת והיא האם זה שכתוב שהחיבור לשרת הצליח משמעות הדבר שאני יכול להיות רגוע שהדוטנט באמת משתמש במחרוזת ההתחברות הנכונה של לינוקס? (השאלה היא האם הוא מתכוון לשרת הכללי או ל-sql-server).
אלף תודות.
-
א. בויזואל סטודיו בפרוייקט דוטנטי אמור להיות קובץ appsettings נפרד למצב פיתוח:
כך ששני המחרוזות והתנאי שעשית, אמורים להיות עבודה מיותרת. אם אני טועה אז עשית מצויין וזה גם עבד לך, כמו שמוכח מהשגיאה.
לעניין השגיאה, נסה להוסיף בסיון מחרוזת החיבור של הDeployedProject את הפרמטר Encrypt=false.נ.ב. הנושא הזה יוצא דופן בפורום פה. יש פה 56 הודעות שהכותרת שלהם היא "תלאות העלאת אתר דוטנט לשרת". אני מאוד אשמח אם משלב זה ואילך תפרסם כל שלב בנושא בפני עצמו בלתי תלוי. למשל, הנושא האחרון הוא שגיאה בחיבור למסד הנתונים MSSQL בשרת אובנטו.
-