External/Internal Sites on T7 & CWBI

You've done a lot of working with npm run dev and now you're ready to get your site off your local workstation so others can see it!


This is a guide on how you might go about doing that. (Let me know in the comments if it needs tweaks/clarification!)


Background

If you are using React + Vite you cannot just paste the source jsx files onto a webserver/T7. You must first build the webapp. This takes those jsx files and transpiles them into 1 JS file and 1 CSS file*. It then places these in a dist directory when you run npm run build.


Then contents of this build directory are what you copy to your T7. 

For the cloud this is a bit different. When you commit to github an action in your .github/workflows/*.yml would run and using this github action it would transpile and bundle your files like above and then this action uses AWS CLI to copy the files to S3 where your dev, test, or prod site are deployed. (Depending on the action file)

Details here: Graham, Charles R CIV USARMY CESWT (USA): Dev > Test > Prod for WM Public Sites | TDL-CESWF-EC-H-National Web Development > How Tos | Microsoft Teams


But now you know you can run npm run build to get this directory with your distribution files in it. How do you move those around to the various places? I mentioned that CWBI/cloud is done via that CI/CD github action. But what about the T7?


T7 React/App files for web

To get static web files (Html/css/js) to your T7 webserver you have a few options. It's worth mentioning that this process is NOT the same for cloud and this is really just to let you (the developer) take advantage of your local webserver you already have in the interim! Perhaps to provide local water management and internal CORPS members a means of testing your internal webapp? 


The tried and true method is to use WinSCP. But after a while you will find with every iteration having to 

  1. npm run build
  2. Login to WinSCP
  3. Remove the files from the last run in the assets directory
  4. Copy the new files over to the directory

This is very tedious!


Instead I recommend that you edit the package.json in the root of your directory (this gets created after you run the setup steps for Groundwork)


And add these lines: 

(Replace the scripts key/value in the file with this)

TAKE CARE

Rename all directory to your district from swt and make sure you WANT to deploy into the root of htdocs as opposed to say htdocs/swt THIS will overwrite files in a given directory. 


These scripts (key/red) will be the npm run dev (which calls the vite command below). So you can make more of these and chain them. This is effectively calling command prompt for you! 

package.json
"scripts": {
    "dev": "vite",
    "build": "vite build --mode t7",
    "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
    "clean-remote": "plink -batch -load CWPT7 \"cd /wm/swt/wm_web/var/apache2/2.4/htdocs/assets/ && rm *.js && rm *.css\"",
    "deploy": "npm run build && npm run clean-remote && pscp -batch -r ./dist/assets/* CWPT7:/wm/swt/wm_web/var/apache2/2.4/htdocs/assets/ && pscp -batch -r ./dist/index.html CWPT7:/wm/swt/wm_web/var/apache2/2.4/htdocs/",
    "deploy-all": "npm run build && npm run clean-remote && pscp -batch -r ./dist/* CWPT7:/wm/swt/wm_web/var/apache2/2.4/htdocs/",
    "preview": "vite preview"
  },



With the putty profile below, you'll be able to run

npm run deploy-all to push public directory and ALL files

and 

npm run deploy to move only the js, html, and css files for smaller pushes!


Credentials? 

You'll notice above I have a -load for the plink command. This loads a putty profile I have named CWPT7


Few things for the profile - this is critical to avoid using a password each time!


Generate a key

  1. Install putty through app portal
  2. Set a keypair by making a key using puttygen (Generate and wiggle mouse!)
  3. Copy the upper contents PUBLIC KEY!!! of puttygen after it generates and paste this into your CWP user ~/.ssh/authorized_keys (MAKE A BACKUP OF THIS FIRST IF YOU ARE UNCERTAIN) i.e.  cp ~/.ssh/authorized_keys ~/.ssh/authorized_keys.bak
  4. Save the private key locally 

    DO NOT SHARE PRIVATE KEY

    (DO NOT COPY private key  TO ANY SERVER!) This should be made PER USER and each user's public key placed in the authorized_keys file. DO NOT SHARE PRIVATE KEY WITH ANYONE.


Setup the putty profile

  1. Open putty.exe
  2. Name your session CWPT7 
  3. Type your T7 IP address for the CWP zone under Host Name (or IP Address)
  4. Click Credentials under Connection > SSH > Auth and Browse to your private key you saved on step # 4 above. 

     

5. Click Data under Connection and enter your CWP user name. I.e. for SWT that's m5cwpa51


Click Session at the top of the side menu and click Save to ensure these changes persist. 


You are now ready to use your putty profile! Test it in windows command prompt with: plink -batch -load CWPT7 whoami
should return your cwp production zone username!


How does routing work for my react app on the T7?

While this is solved for you on the cloud site. It is not on the T7. 

You will need to put a ticket in with G6. I recommend you search "CWMS Ticket" and assign it as NOT CRITICAL to the WEB TEAM. 


Depending on where you want the site pushed to. 


I.e. is this in the root of your htdocs or is this in a sub directory i.e. /htdocs/swt


G6 (normally Mark Carron) will be able to setup the clientside routing for you. The basic configuration for apache /htdocs is this:

Apache Reverse Proxy
<Directory "/wm/swt/wm_web/var/apache2/2.4/htdocs">
# If not already on
RewriteEngine On
    # Don't rewrite files or directories
    RewriteCond %{REQUEST_FILENAME} -f [OR]
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule ^ - [L]
    # Rewrite everything else to index.html to allow html5 state links
    RewriteRule ^ index.html [L]
</Directory>
 




You can see this is looking for a file or directory and if it does not exist it will rewrite the path to your index.html file at the root. The key piece is this block IS FOR THE ROOT OF THE WEBSERVER. 


This allows React + Redux to handle client-side routing. I.e. javascript handles sub pages instead of you having multiple index.html files you now have one. A single page application (SPA) 

COOP?

SWT has a nighly rsync task that copies all web files to our coop!

`15 0 * * * /wm/swt/localsoft/cwms/bin/cwmsenv /wm/swt/##cwpuser##/bin/syncCoopWeb.sh >/dev/null 2>&1`


This file /wm/swt/m5cwpa51/bin/syncCoopWeb.sh contains:

syncCoopWeb.sh
# Nightly backup of the entire web directory.
# The exclude list ignores the big directories with rotating hourly txt files (and some others)
# Charles Graham - 07/2023

# Writeup of what these params do
#================================
# -a, --archive: This option enables the archive mode, which is a combination of several other options.
#   It preserves permissions, ownership, modification times, and symbolic links, and it recurses into directories.
#   It's a convenient way to ensure that the files are copied with the same attributes as the original.
#     This assumes the server you copy to has the same service user/folder structure.
#
# -v, --verbose: This option enables verbose output, providing more detailed information during the synchronization process.
#   It shows the files being transferred and other progress details.
#    If you plan to log the output I would remove this flag!
#
# -z, --compress: This option enables data compression during the transfer,
#   which can reduce the network usage and speed up the transfer, especially for large files.
#    Make sure to use this! We have plenty of CPU but the bandwidth is limited in a COOP setup.
#
# --no-p, --no-perms: This option tells rsync not to preserve the permissions of the transferred files.
#   It's useful when you want to avoid setting specific permissions on the destination files.
#
# --no-t, --no-times: This option prevents rsync from preserving the modification times of the transferred files.
#   It's useful when you don't want the timestamps of the destination files to be updated.
#    NOTE: You will get errors if you do NOT include this and --no-p.
#       Rsync will try to change perms of EVERY directory even ones it does not own working
#           it's way up to the web dirs (when using relative)
#
# --update: The update option ensures that rsync only transfers files from the source to the destination
#   if the source file is newer than the corresponding file on the destination.
#   It helps in copying only the files that have been updated, which saves time and bandwidth.
#
# --progress: This option shows progress information during the synchronization process,
#    indicating how much data has been transferred and the estimated time remaining.
#     If you plan to log the output I would remove this flag!
#
# --exclude-from=rsync_exclude.txt: This option excludes files or directories listed
#   in the rsync_exclude.txt file from being transferred. You can specify a list of patterns or directories to exclude, one per line, in the file.
#   SWT places theirs in ~/config/rsync_exclude.txt
#    Here is an example of what we have in this directory (no spaces before/after)
#      /wm/swt/wm_web/var/apache2/2.4/htdocs/videos
#      /wm/swt/wm_web/var/apache2/2.4/htdocs/webdata/dcptxsum
#      /wm/swt/wm_web/var/apache2/2.4/htdocs/webdata/gagedata
#
# --relative: The relative option ensures that rsync preserves the directory structure relative to the
#   current working directory on the destination server. It maintains the relative paths of the files and directories.
#
# $WEB_DIR/: This is the source directory that you want to synchronize. Replace $WEB_DIR with the actual
#   path to your source directory.
#
# user@host:/: This is the destination address where the files will be copied.
#   Replace user with the username on the destination server, and host with the hostname or IP address of the destination server.
#   The trailing / indicates the root directory of the destination.

export HTDOCS=/wm/swt/wm_web/var/apache2/2.4/htdocs
export CGIBIN=/wm/swt/wm_web/var/apache2/2.4/cgi-bin
# $COOP_LOGIN is an alias that is set in the .bashrc file
# This command assumes that you have your service user's public key in the authorized_keys file of your coop server's user .ssh directory!
# Otherwise you will get prompted for passwords and it will not work in cron
rsync -avz --no-p --no-t --delete --update --progress --exclude-from=/wm/swt/m5cwpa51/config/rsync_exclude.txt --relative $HTDOCS/  coopuser@coophostname:/
rsync -avz --no-p --no-t --delete --update --progress --exclude-from=/wm/swt/m5cwpa51/config/rsync_exclude.txt --relative $CGIBIN/  coopuser@coophostname:/
 



 /wm/swt/cwpuser/config/rsync_exclude.txt

/wm/swt/wm_web/var/apache2/2.4/htdocs/videos
/wm/swt/wm_web/var/apache2/2.4/htdocs/webdata/dcptxsum
/wm/swt/wm_web/var/apache2/2.4/htdocs/webdata/gagedata

 


TDL-CESWF-EC-H-National Web Development