@@ -20,7 +20,7 @@ public function build_le_cert( $user ) {
2020 global $ hcpp ;
2121 $ domain = $ this ->get_base_domain ();
2222
23- // Check if the LE certificate already exists .
23+ // Check time of existing LE cert. file .
2424 $ cert_file = "/home/ $ user/conf/web/vscode- $ user. $ domain/ssl/vscode- $ user. $ domain.pem " ;
2525 if ( file_exists ( $ cert_file ) ) {
2626 // Get the file modification time
@@ -36,28 +36,36 @@ public function build_le_cert( $user ) {
3636 }
3737 unlink ( $ cert_file );
3838 }
39+
40+ // Check if the LE cert. file exists.
41+ if ( file_exists ( $ cert_file ) ) {
42+ $ hcpp ->log ( "LE certificate already exists for vscode- $ user. $ domain " );
43+ return ;
44+ }
45+
3946 $ ip = array_key_first ( $ hcpp ->run ( "list-user-ips $ user json " ) );
4047
4148 // Get the admin user email address
4249 $ email = trim ( $ hcpp ->run ( 'list-user admin json ' )['admin ' ]['CONTACT ' ] );
4350
44- // Swap out nginx. conf and nginx.ssl.conf files to use the LE webroot
45- $ ssl_conf = " /home/ $ user /conf/web/ vscode-$ user. $ domain/ nginx.ssl.conf " ;
46- $ conf = " /home/ $ user /conf/web/vscode- $ user . $ domain /nginx.conf " ;
47- $ ssl_sav = "/home/ $ user/conf/web/vscode- $ user. $ domain/nginx.ssl.sav " ;
48- $ sav = "/home/ $ user/conf/web/vscode- $ user. $ domain/nginx.sav " ;
49- rename ( $ ssl_conf , $ ssl_sav );
50- rename ( $ conf, $ sav );
51-
52- // Turn off force SSL
53- $ force_ssl_conf = " /home/ $ user /conf/web/vscode- $ user . $ domain /nginx.forcessl.conf " ;
54- $ force_ssl_sav = " /home/ $ user /conf/web/vscode- $ user . $ domain /nginx.forcessl.sav " ;
55- rename ( $ force_ssl_conf , $ force_ssl_sav );
56-
57- // Create empty nginx.ssl.conf file
58- touch ( $ ssl_conf );
59-
51+ // Clean existing conf files and links
52+ $ hcpp -> log ( " Missing certificate for vscode-$ user. $ domain; skipping nginx configuration " ) ;
53+ $ files = [
54+ "/home/ $ user/conf/web/vscode- $ user. $ domain/nginx.ssl.conf " ,
55+ "/home/ $ user/conf/web/vscode- $ user. $ domain/nginx.conf " ,
56+ " /home/ $ user /conf/web/vscode- $ user . $ domain /nginx.forcessl.conf " ,
57+ " /etc/nginx/conf.d/domains/vscode- $ user . $ domain . conf" ,
58+ " /etc/nginx/conf.d/domains/vscode- $ user . $ domain .ssl.conf "
59+ ];
60+
61+ foreach ( $ files as $ file ) {
62+ if ( file_exists ( $ file ) ) {
63+ unlink ( $ file );
64+ }
65+ }
66+
6067 // Create nginx.conf that serves up le-webroot folder
68+ $ conf = $ files [1 ];
6169 @mkdir ( "/home/ $ user/conf/web/vscode- $ user. $ domain/le-webroot " , 0755 , true );
6270 @mkdir ( "/home/ $ user/conf/web/vscode- $ user. $ domain/ssl " , 0755 , true );
6371 $ content = 'server {
@@ -79,34 +87,36 @@ public function build_le_cert( $user ) {
7987 $ hcpp ->log ( 'Restart nginx to serve le-webroot: ' . shell_exec ($ cmd ) );
8088
8189 // Use certbot to generate the LE certificate
82- $ cmd = "certbot certonly --webroot -w /home/ $ user/conf/web/vscode- $ user. $ domain/le-webroot -d vscode- $ user. $ domain --email $ email --agree-tos --non-interactive " ;
83- $ cmd = $ hcpp ->do_action ( 'vscode_build_le_cert ' , $ cmd );
84- exec ( $ cmd , $ output , $ return_var );
85- if ( $ return_var !== 0 ) {
86- $ hcpp ->log ("Failed to generate LE certificate: " . implode ("\n" , $ output ));
87- } else {
90+ $ cmd = "certbot certonly --webroot -w /home/ $ user/conf/web/vscode- $ user. $ domain/le-webroot -d vscode- $ user. $ domain --email $ email --agree-tos --non-interactive 2>&1 " ;
91+ $ cmd = $ hcpp ->do_action ( 'vscode_generate_le_cert ' , $ cmd );
92+ $ output = shell_exec ( $ cmd );
93+ $ hcpp ->log ( "Generate LE certificate: " . $ output );
94+
95+ $ cert_file = "/etc/letsencrypt/live/vscode- $ user. $ domain/fullchain.pem " ;
96+ $ key_file = "/etc/letsencrypt/live/vscode- $ user. $ domain/privkey.pem " ;
97+ $ cert_link = "/home/ $ user/conf/web/vscode- $ user. $ domain/ssl/vscode- $ user. $ domain.pem " ;
98+ $ key_link = "/home/ $ user/conf/web/vscode- $ user. $ domain/ssl/vscode- $ user. $ domain.key " ;
99+
100+ if ( file_exists ( $ cert_file ) ) {
88101
89102 // Link to the LE certificate and key
90- $ hcpp ->log ("Successfully generated LE certificate: " . implode ("\n" , $ output ));
91- $ cert_file = "/etc/letsencrypt/live/vscode- $ user. $ domain/fullchain.pem " ;
92- $ key_file = "/etc/letsencrypt/live/vscode- $ user. $ domain/privkey.pem " ;
93- $ cert_link = "/home/ $ user/conf/web/vscode- $ user. $ domain/ssl/vscode- $ user. $ domain.pem " ;
94- $ key_link = "/home/ $ user/conf/web/vscode- $ user. $ domain/ssl/vscode- $ user. $ domain.key " ;
103+ $ hcpp ->log ("Successfully generated LE certificate " );
95104 @symlink ( $ cert_file , $ cert_link );
96105 @symlink ( $ key_file , $ key_link );
97- }
98-
99- // Restore the original nginx.conf and nginx.ssl.conf and force_ssl files
100- if ( file_exists ( $ ssl_conf ) ) unlink ( $ ssl_conf );
101- rename ( $ ssl_sav , $ ssl_conf );
102- if ( file_exists ( $ conf ) ) unlink ( $ conf );
103- rename ( $ sav , $ conf );
104- if ( file_exists ( $ force_ssl_conf ) ) unlink ( $ force_ssl_conf );
105- rename ( $ force_ssl_sav , $ force_ssl_conf );
106+ }else {
107+ $ hcpp ->log ("Failed to generate LE certificate: " );
106108
107- // Restart nginx to serve vscode- folder
108- $ cmd = '/usr/sbin/service nginx restart 2>&1 ' ;
109- $ hcpp ->log ( 'Restart nginx to serve -vscode: ' . shell_exec ($ cmd ) );
109+ // Cleanup files
110+ $ files = [
111+ $ cert_link ,
112+ $ key_link
113+ ];
114+ foreach ( $ files as $ file ) {
115+ if ( file_exists ( $ file ) ) {
116+ unlink ( $ file );
117+ }
118+ }
119+ }
110120 }
111121
112122 /**
@@ -323,31 +333,55 @@ public function get_most_recently_modified_file( $base_path ) {
323333 */
324334 public function startup ( $ user ) {
325335 global $ hcpp ;
336+ $ domain = $ this ->get_base_domain ();
337+ $ cert_file = "/home/ $ user/conf/web/vscode- $ user. $ domain/ssl/vscode- $ user. $ domain.pem " ;
326338
327- // Check for existing instance of VSCode's "server-main.js" for the user.
328- $ cmd = "ps axo user:20,pid,args | grep \"/opt/vscode/node /opt/vscode/out/server-main.js \" | grep $ user | grep -v grep | awk '{print $2}' " ;
329- $ pid = trim ( shell_exec ( $ cmd ) );
330-
331- // Start the vscode server for the given user if not already running.
332- if ( $ pid ) {
333- $ hcpp ->log ( "VSCode server $ pid, already running for $ user " );
334- touch ( "/home/ $ user/.openvscode-server/data/token " ); // Keep idle server alive
335- return ;
339+ // Generate website cert if it doesn't exist.
340+ if ( !file_exists ( $ cert_file ) ) {
341+
342+ // Generate website cert if it doesn't exist for Devstia Personal Web edition.
343+ if ( property_exists ( $ hcpp , 'dev_pw ' ) ) {
344+
345+ // Always regenerate the cert to ensure it's up to date.
346+ $ hcpp ->dev_pw ->generate_website_cert ( $ user , ["vscode- $ user. $ domain " ] );
347+ }else {
348+
349+ // Support LE SSL certs for non-Devstia Personal Web edition.
350+ $ this ->build_le_cert ( $ user );
351+
352+ }
336353 }
337- $ hcpp ->log ( "Setting up VSCode for $ user " );
338- $ domain = $ this ->get_base_domain ();
339354
340- // Get user account first IP address.
341- $ ip = array_key_first ( $ hcpp ->run ( "list-user-ips $ user json " ) );
355+ // Skip/remove nginx configuration files if cert is missing.
356+ if ( !file_exists ( $ cert_file ) ) {
357+ $ hcpp ->log ( "Missing certificate for vscode- $ user. $ domain; skipping nginx configuration " );
358+ $ files = [
359+ "/home/ $ user/conf/web/vscode- $ user. $ domain/nginx.ssl.conf " ,
360+ "/home/ $ user/conf/web/vscode- $ user. $ domain/nginx.conf " ,
361+ "/home/ $ user/conf/web/vscode- $ user. $ domain/nginx.forcessl.conf " ,
362+ "/etc/nginx/conf.d/domains/vscode- $ user. $ domain.conf " ,
363+ "/etc/nginx/conf.d/domains/vscode- $ user. $ domain.ssl.conf "
364+ ];
342365
343- // Get a port for the VSCode service.
344- $ port = $ hcpp ->allocate_port ( 'vscode ' , $ user );
366+ foreach ( $ files as $ file ) {
367+ if ( file_exists ( $ file ) ) {
368+ unlink ( $ file );
369+ }
370+ }
371+ return ;
372+ }
345373
346374 // Create the configuration folder.
347375 if ( ! is_dir ( "/home/ $ user/conf/web/vscode- $ user. $ domain " ) ) {
348376 mkdir ( "/home/ $ user/conf/web/vscode- $ user. $ domain " );
349377 }
350378
379+ // Get user account first IP address.
380+ $ ip = array_key_first ( $ hcpp ->run ( "list-user-ips $ user json " ) );
381+
382+ // Get a port for the VSCode service.
383+ $ port = $ hcpp ->allocate_port ( 'vscode ' , $ user );
384+
351385 // Create the nginx.conf file.
352386 $ conf = "/home/ $ user/conf/web/vscode- $ user. $ domain/nginx.conf " ;
353387 $ content = file_get_contents ( __DIR__ . '/conf-web/nginx.conf ' );
@@ -358,6 +392,12 @@ public function startup( $user ) {
358392 );
359393 file_put_contents ( $ conf , $ content );
360394
395+ // Create the nginx.conf symbolic link.
396+ $ link = "/etc/nginx/conf.d/domains/vscode- $ user. $ domain.conf " ;
397+ if ( ! is_link ( $ link ) ) {
398+ symlink ( $ conf , $ link );
399+ }
400+
361401 // Create the nginx.ssl.conf file.
362402 $ ssl_conf = "/home/ $ user/conf/web/vscode- $ user. $ domain/nginx.ssl.conf " ;
363403 $ content = file_get_contents ( __DIR__ . '/conf-web/nginx.ssl.conf ' );
@@ -368,48 +408,46 @@ public function startup( $user ) {
368408 );
369409 file_put_contents ( $ ssl_conf , $ content );
370410
371- // Generate website cert if it doesn't exist for Devstia Personal Web edition.
372- if ( property_exists ( $ hcpp , 'dev_pw ' ) ) {
373-
374- // Always regenerate the cert to ensure it's up to date.
375- $ hcpp ->dev_pw ->generate_website_cert ( $ user , ["vscode- $ user. $ domain " ] );
376- }else {
411+ // Create the nginx.ssl.conf symbolic link.
412+ $ link = "/etc/nginx/conf.d/domains/vscode- $ user. $ domain.ssl.conf " ;
413+ if ( ! is_link ( $ link ) ) {
414+ symlink ( $ ssl_conf , $ link );
415+ }
377416
378- // Force SSL on non-Devstia Personal Web edition.
417+ // Create the force SSL conf file on non-Devstia Personal Web edition.
418+ if ( !property_exists ( $ hcpp , 'dev_pw ' ) ) {
379419 $ force_ssl_conf = "/home/ $ user/conf/web/vscode- $ user. $ domain/nginx.forcessl.conf " ;
380420 $ content = "return 301 https:// \$host \$request_uri; " ;
381421 file_put_contents ( $ force_ssl_conf , $ content );
382-
383- // Support LE SSL certs for non-Devstia Personal Web edition.
384- $ this ->build_le_cert ( $ user );
385422 }
386423
387- // Create the nginx.conf configuration symbolic links.
388- $ link = "/etc/nginx/conf.d/domains/vscode- $ user. $ domain.conf " ;
389- if ( ! is_link ( $ link ) ) {
390- symlink ( $ conf , $ link );
391- }
392-
393- // Create the nginx.ssl.conf configuration symbolic links.
394- $ link = "/etc/nginx/conf.d/domains/vscode- $ user. $ domain.ssl.conf " ;
395- if ( ! is_link ( $ link ) ) {
396- symlink ( $ ssl_conf , $ link );
424+ // Check for existing instance of VSCode's "server-main.js" for the user.
425+ $ cmd = "ps axo user:20,pid,args | grep \"/opt/vscode/node /opt/vscode/out/server-main.js \" | grep $ user | grep -v grep | awk '{print $2}' " ;
426+ $ pid = trim ( shell_exec ( $ cmd ) );
427+
428+ // Start the vscode server for the given user if not already running.
429+ if ( $ pid ) {
430+ $ hcpp ->log ( "VSCode server $ pid, already running for $ user " );
431+ touch ( "/home/ $ user/.openvscode-server/data/token " ); // Keep idle server alive
432+ }else {
433+ $ hcpp ->log ( "Setting up VSCode for $ user " );
434+
435+ // Create VSCode token if it doesn't already exist.
436+ $ this ->update_token ( $ user );
437+
438+ // Start the VSCode service manually (outside of PM2).
439+ $ cmd = 'runuser -l ' . $ user . ' -c " ' ;
440+ $ cmd .= "(/opt/vscode/node /opt/vscode/out/server-main.js --port $ port) > /dev/null 2>&1 & " ;
441+ $ cmd .= '" ' ;
442+ $ cmd = $ hcpp ->do_action ( 'vscode_nodejs_cmd ' , $ cmd );
443+ shell_exec ( $ cmd );
444+
445+ // Reload nginx
446+ $ cmd = '(service nginx restart) > /dev/null 2>&1 & ' ;
447+ $ cmd = $ hcpp ->do_action ( 'vscode_nginx_restart ' , $ cmd );
448+ shell_exec ( $ cmd );
397449 }
398450
399- // Create VSCode token if it doesn't already exist.
400- $ this ->update_token ( $ user );
401-
402- // Start the VSCode service manually (outside of PM2).
403- $ cmd = 'runuser -l ' . $ user . ' -c " ' ;
404- $ cmd .= "(/opt/vscode/node /opt/vscode/out/server-main.js --port $ port) > /dev/null 2>&1 & " ;
405- $ cmd .= '" ' ;
406- $ cmd = $ hcpp ->do_action ( 'vscode_nodejs_cmd ' , $ cmd );
407- shell_exec ( $ cmd );
408-
409- // Reload nginx
410- $ cmd = '(service nginx restart) > /dev/null 2>&1 & ' ;
411- $ cmd = $ hcpp ->do_action ( 'vscode_nginx_restart ' , $ cmd );
412- shell_exec ( $ cmd );
413451 }
414452
415453 /**
0 commit comments