{"id":18736766,"url":"https://github.com/selvasingh/tomcat-on-virtual-machine","last_synced_at":"2026-04-13T19:32:07.996Z","repository":{"id":82967613,"uuid":"322202008","full_name":"selvasingh/tomcat-on-virtual-machine","owner":"selvasingh","description":"How to deploy a real-world Java app to Tomcat on Azure Linux Virtual Machines?","archived":false,"fork":false,"pushed_at":"2020-12-23T00:35:40.000Z","size":4133,"stargazers_count":0,"open_issues_count":3,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-25T23:36:52.646Z","etag":null,"topics":["airsonic","azure","azure-virtual-machine","java","java-8","linux","mysql","mysql-database","newrelic","spring","spring-boot","tomcat"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/selvasingh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-12-17T06:28:01.000Z","updated_at":"2020-12-23T00:35:42.000Z","dependencies_parsed_at":null,"dependency_job_id":"227d950a-db87-46c3-a680-e3bd1f414095","html_url":"https://github.com/selvasingh/tomcat-on-virtual-machine","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/selvasingh/tomcat-on-virtual-machine","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/selvasingh%2Ftomcat-on-virtual-machine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/selvasingh%2Ftomcat-on-virtual-machine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/selvasingh%2Ftomcat-on-virtual-machine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/selvasingh%2Ftomcat-on-virtual-machine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/selvasingh","download_url":"https://codeload.github.com/selvasingh/tomcat-on-virtual-machine/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/selvasingh%2Ftomcat-on-virtual-machine/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31768636,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-13T15:25:13.801Z","status":"ssl_error","status_checked_at":"2026-04-13T15:25:09.162Z","response_time":93,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["airsonic","azure","azure-virtual-machine","java","java-8","linux","mysql","mysql-database","newrelic","spring","spring-boot","tomcat"],"created_at":"2024-11-07T15:22:24.426Z","updated_at":"2026-04-13T19:32:07.972Z","avatar_url":"https://github.com/selvasingh.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"---\npage_type: sample\nlanguages:\n- java\nproducts:\n- azure\n- azure-virtual-machines\n- MySQL\nextensions:\n- services: MySQL\n- platforms: java\ndescription: \"Deploy Java app to Tomcat in Azure Linux Virtual Machine\"\nurlFragment: \"tomcat-on-virtual-machine\"\n---\n \n# Deploy Java app to Tomcat on Azure Linux Virtual Machines\n\nAzure Linux Virtual Machines are versatile and \naccomodate any Java app types. This repo walks you through how to deploy\na real-world Java app to Tomcat on Azure Linux Virtual Machines.\n\n## What will you experience\nYou will:\n- Create a Linux virtual machine\n- Install Apache Tomcat 9\n- Deploy a real-world application to Tomcat 9 and install application dependencies\n- Bind the application to Azure Database for MySQL\n- Open the application\n- Monitor application using Application Insights or APMs of your choice - New Relic, App Dynamics or Dynatrace.\n\n## What you will need\n\nIn order to deploy a Java app to cloud, you need \nan Azure subscription. If you do not already have an Azure \nsubscription, you can activate your \n[MSDN subscriber benefits](https://azure.microsoft.com/pricing/member-offers/msdn-benefits-details/) \nor sign up for a \n[free Azure account]((https://azure.microsoft.com/free/)).\n\nIn addition, you will need the following:\n\n| [Azure CLI](https://docs.microsoft.com/cli/azure/install-azure-cli?view=azure-cli-latest) \n| [MySQL CLI](https://dev.mysql.com/downloads/shell/)\n|\n\n## Prepare dev machine\n\nCreate a bash script with environment variables by making a copy of the supplied template:\n```bash\ncp .scripts/setup-env-variables-azure-template.sh .scripts/setup-env-variables-azure.sh\n```\n\nOpen `.scripts/setup-env-variables-azure.sh` and enter the following information:\n\n```bash\n\n# Supply Azure Subscription information\nexport SUBSCRIPTION=my-subscription-id # customize this\n\n# Suppy Your Resource Group and Linux Virtual Machine info\nexport RESOURCE_GROUP=tomcat-iaas-12-2020 # customize this\nexport REGION=westus2 # customize this\nexport ADMIN_USERNAME=vm-admin-name # customize this\n\n# Supply MySQL Database info\nexport MYSQL_SERVER_NAME=mysql-server-name # customize this\nexport MYSQL_SERVER_ADMIN_NAME=admin-name # customize this\nexport MYSQL_SERVER_ADMIN_PASSWORD=SuperS3cr3t # customize this\n\n# Supply Password for airsonic app\nexport AIRSONIC_ADMIN_PASSWORD=SuperS3cr3t # customize this\n\n```\n\nThen, set the environment:\n```bash\n    source .scripts/setup-env-variables-azure.sh\n```\n\nLogin to the Azure CLI and choose your active subscription. Be sure to choose the active subscription that is whitelisted for Azure Spring Cloud\n\n```bash\n    az login\n    az account list -o table\n    az account set --subscription ${SUBSCRIPTION}\n```\n\n## Create a Linux Virtual Machine with Java\n\nCreate a Linux Virtual Machine with Java using a quick start template. \nAccept all defaults in the template and modify the following parameters:\n- Resource Group = `${RESOURCE_GROUP}`\n- Admin Username = `${ADMIN_USERNAME}`\n- Admin Key = `Your SSH Public Key`\n- Public IP Sku =  `Standard`\n \n\u003ca href=\"https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fazure-quickstart-templates%2Fmaster%2F101-Linux-Java-ZuluOpenJDK%2Fazuredeploy.json\" target=\"_blank\"\u003e\n    \u003cimg src=\"https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/1-CONTRIBUTION-GUIDE/images/deploytoazure.svg?sanitize=true\"/\u003e\n\u003c/a\u003e\n\nAttach a 30 GB data disk to the virtual machine as described in [how to create and attach a\ndata disk](https://docs.microsoft.com/en-us/azure/virtual-machines/linux/attach-disk-portal). As described\nin the document, open an SSH connection to the Linux Virtual Machine and mount the new disk.\n\n# Install Apache Tomcat\n\n[GET VM IP Address]\n\nOpen an SSH connection to the Linux Virtual Machine and install tomcat:\n\n```bash\n# Log into SSH session\nssh ${ADMIN_USERNAME}@${VM_IP_ADDRESS}\n\n# Create a tomcat9 group\nsudo groupadd tomcat9\n\n# Create a new tomcat9 user\nsudo useradd -s /bin/false -g tomcat9 -d /opt/tomcat9 tomcat9\n\n# Download Apache Tomcat\ncd /tmp\ncurl -O https://downloads.apache.org/tomcat/tomcat-9/v9.0.41/bin/apache-tomcat-9.0.41.tar.gz\n\n# Install tomcat in /opt/tomcat9 directory\nsudo mkdir /opt/tomcat9\nsudo tar xzvf apache-tomcat-*tar.gz -C /opt/tomcat9 --strip-components=1\n\n# Update permissions for tomcat9 directory\ncd /opt/tomcat9\nsudo chgrp -R tomcat9 /opt/tomcat9\n\n# Give tomcat9 group read access\nsudo chmod -R g+r conf\nsudo chmod g+x conf\n\n# Make the tomcat user the owner of the Web apps, work, temp, and logs directories:\nsudo chown -R tomcat9 webapps/ work/ temp/ logs/\n\n# ==== Create a systemd Service File\n# find JAVA_HOME\nsudo update-java-alternatives -l\n# zulu-8-azure-amd64             1805006    /usr/lib/jvm/zulu-8-azure-amd64\n\n# Open a file called tomcat9.service in the /etc/systemd/system\nsudo nano /etc/systemd/system/tomcat9.service\n```\n\nConfigure `tomcat9` as a service:\n\n```text\n# add the following to the /etc/systemd/system/tomcat9.service file\n\n[Unit]\nDescription=Apache Tomcat Web Application Container\nAfter=network.target\n\n[Service]\nType=forking\n\nEnvironment=JAVA_HOME=/usr/lib/jvm/zulu-8-azure-amd64\nEnvironment=CATALINA_PID=/opt/tomcat9/temp/tomcat.pid\nEnvironment=CATALINA_HOME=/opt/tomcat9\nEnvironment=CATALINA_BASE=/opt/tomcat9\nEnvironment='CATALINA_OPTS=-Xms8192M -Xmx8192M -server -XX:+UseParallelGC'\nEnvironment='JAVA_OPTS=-Djava.awt.headless=true -Djava.security.egd=file:/dev/./urandom'\n\nExecStart=/opt/tomcat9/bin/startup.sh\nExecStop=/opt/tomcat9/bin/shutdown.sh\n\nUser=tomcat9\nGroup=tomcat9\nUMask=0007\nRestartSec=10\nRestart=always\n\n[Install]\nWantedBy=multi-user.target\n```\n\n```bash\n# reload the systemd daemon so that it knows about our service file\nsudo systemctl daemon-reload\nsudo systemctl start tomcat9\n```\n\nCustomize Tomcat:\n```bash\n# Configure Tomcat 9\n# Configure management user\nsudo nano /opt/tomcat9/conf/tomcat-users.xml\n```\n\nAdd a user with access to Tomcat Manager and Tools:\n\n```xml\n\u003ctomcat-users\u003e\n    \u003crole rolename=\"manager-gui\"/\u003e\n    \u003crole rolename=\"admin-gui\"/\u003e\n    \u003crole rolename=\"manager-script\"/\u003e\n    \u003cuser username=\"manager\" password=\"SuperS3cr3t\" roles=\"manager-gui,admin-gui,manager-script\"/\u003e\n\u003c/tomcat-users\u003e\n```\n\nContinue to customize Tomcat:\n```bash\n# For the Manager app, type:\nsudo nano /opt/tomcat9/webapps/manager/META-INF/context.xml\n\n# For the Host Manager app, type:\nsudo nano /opt/tomcat9/webapps/host-manager/META-INF/context.xml\n\n# Inside, comment out the IP address restriction to allow connections from anywhere.\n# Alternatively, if you would like to allow access only to connections \n# coming from your own IP address, you can add your public IP address to the list in\n# context.xml files for Tomcat web apps\n```\n```xml\n\u003cContext antiResourceLocking=\"false\" privileged=\"true\" \u003e\n  \u003c!--\u003cValve className=\"org.apache.catalina.valves.RemoteAddrValve\"\n         allow=\"127\\.\\d+\\.\\d+\\.\\d+|::1|0:0:0:0:0:0:0:1\" /\u003e--\u003e\n\u003c/Context\u003e\n```\n```bash\n# Restart tomcat 9\nsudo systemctl stop tomcat9\nsudo systemctl start tomcat9\n\n# Check the status of tomcat 9\nsudo systemctl status tomcat9\n\n# Enable the service file so that Tomcat automatically starts at boot:\nsudo systemctl enable tomcat9\n```\n\nFrom your dev machine, open up ports to access Tomcat\n```bash\n# Open up ports from your dev machine\naz vm open-port --port 8080 --resource-group ${RESOURCE_GROUP} --name ${VM_NAME} --priority 1100\n```\n\n# Install airsonic application\n\nReopen an SSH connection into the Linux Virtual Machine:\n\n```bash\n# Log into SSH session\nssh ${ADMIN_USERNAME}@${VM_IP_ADDRESS}\n\ncd /tmp\n\n# Download airsonic WAR package\nwget https://github.com/airsonic/airsonic/releases/download/v10.6.2/airsonic.war\n\n# Download and import Andrew DeMaria public key:\ngpg --keyserver keyserver.ubuntu.com --recv 0A3F5E91F8364EDF\n\n# Download the signed checksums file and verify the previously download .war package:\n\nwget https://github.com/airsonic/airsonic/releases/download/v10.6.2/artifacts-checksums.sha.asc\ngpg --verify artifacts-checksums.sha.asc\nsha256sum -c artifacts-checksums.sha.asc\n\n# Create the airsonic directory and assign ownership to the \n# Tomcat system user (if running Tomcat as a service):\n\nsudo mkdir /datadrive/airsonic/\nsudo chown -R tomcat9:tomcat9 /datadrive/airsonic/\n\n# Stop Tomcat 9\nsudo systemctl stop tomcat9\n\n# Move airsonic into Tomcat 9\n# Move the downloaded WAR file in the $TOMCAT_HOME/webapps \n# folder and assign ownership to the Tomcat system user:\nsudo mv airsonic.war /opt/tomcat9/webapps/airsonic.war\nsudo chown tomcat9:tomcat9 /opt/tomcat9/webapps/airsonic.war\n\n# add Read Write paths to Tomcat\nsudo nano /etc/systemd/system/tomcat9.service\n```\n\nAdd `Read` and `Write` paths, and airsonic home directory to \nTomcat systemd service definition by adding `ReadWritePaths=/datadrive/airsonic/`\nto systemd service definition and adding `-Dairsonic.home=/datadrive/airsonic` \nto `JAVA_OPTS` environment variable:\n```text\n[Unit]\nDescription=Apache Tomcat Web Application Container\nAfter=network.target\n\n[Service]\nType=forking\n\nEnvironment=JAVA_HOME=/usr/lib/jvm/zulu-8-azure-amd64\nEnvironment=CATALINA_PID=/opt/tomcat9/temp/tomcat.pid\nEnvironment=CATALINA_HOME=/opt/tomcat9\nEnvironment=CATALINA_BASE=/opt/tomcat9\nEnvironment='CATALINA_OPTS=-Xms512M -Xmx1024M -server -XX:+UseParallelGC'\nEnvironment='JAVA_OPTS=-Djava.awt.headless=true -Djava.security.egd=file:/dev/./urandom -Dairsonic.home=/datadrive/airsonic'\n\nExecStart=/opt/tomcat9/bin/startup.sh\nExecStop=/opt/tomcat9/bin/shutdown.sh\n\nUser=tomcat9\nGroup=tomcat9\nUMask=0007\nRestartSec=10\nRestart=always\n\nReadWritePaths=/datadrive/airsonic/\n\n[Install]\nWantedBy=multi-user.target\n```\n\nModify the Tomcat `server.xml`:\n\n```bash\n# Edit server.xml\nsudo nano /opt/tomcat9/conf/server.xml\n```\n\nYou will need to add the following right above the `\u003c/Host\u003e` tag in `server.xml`:\n```xml\n        \u003cContext path=\"\" docBase=\"airsonic\" debug=\"0\" reloadable=\"true\"\u003e\n                \u003cWatchedResource\u003eWEB-INF/web.xml\u003c/WatchedResource\u003e\n        \u003c/Context\u003e\n        \u003cContext path=\"ROOT\" docBase=\"ROOT\"\u003e \u003c!-- Default set of monitored resources --\u003e\n                \u003cWatchedResource\u003eWEB-INF/web.xml\u003c/WatchedResource\u003e\n        \u003c/Context\u003e\n```\n\n```bash\n# Reload the systemd configuration:\nsudo systemctl daemon-reload\n\n# Install ffmpeg package:\n# Reference https://airsonic.github.io/docs/transcode/#on-ubuntu--1604\nsudo snap install ffmpeg\n\n# Create a transcode directory within your AIRSONIC_HOME directory:\n\nsudo mkdir /datadrive/airsonic/transcode\n\n# Within the transcode directory symlink to ffmpeg and verify correct permissions:\n\ncd /datadrive/airsonic/transcode/\nsudo ln -s /usr/bin/ffmpeg\nsudo chown -h tomcat9:tomcat9 ffmpeg\nls -alh\n\n# create music, media, podcasts and playlists folders\ncd /datadrive/airsonic/\nsudo mkdir music\nsudo mkdir media\nsudo mkdir podcasts\nsudo mkdir playlists\n\nsudo chown -R tomcat9 transcode/ music/ media/ podcasts/ playlists/\nsudo chmod 777 /datadrive/airsonic/music\n\n# =============================\n```\n\n## Create a MySQL database\n\nFrom your dev machine, create a MySQL database:\n\n```bash\n# Create mysql server\naz mysql server create --resource-group ${RESOURCE_GROUP} \\\n --name ${MYSQL_SERVER_NAME}  --location ${REGION} \\\n --admin-user ${MYSQL_SERVER_ADMIN_NAME} \\\n --admin-password ${MYSQL_SERVER_ADMIN_PASSWORD} \\\n --sku-name GP_Gen5_2 \\\n --ssl-enforcement Disabled \\\n --version 5.7\n\n# Allow access from Azure resources\naz mysql server firewall-rule create --name allAzureIPs \\\n --server ${MYSQL_SERVER_NAME} \\\n --resource-group ${RESOURCE_GROUP} \\\n --start-ip-address 0.0.0.0 --end-ip-address 0.0.0.0\n\n# Allow access from your dev machine for testing\naz mysql server firewall-rule create --name devMachine \\\n --server ${MYSQL_SERVER_NAME} \\\n --resource-group ${RESOURCE_GROUP} \\\n --start-ip-address \u003cip-address-of-your-dev-machine\u003e \\\n --end-ip-address \u003cip-address-of-your-dev-machine\u003e\n\n# Increase connection timeout\naz mysql server configuration set --name wait_timeout \\\n --resource-group ${RESOURCE_GROUP} \\\n --server ${MYSQL_SERVER_NAME} --value 2147483\n\n# Connect to MySQL Server\nmysql -u ${MYSQL_SERVER_ADMIN_LOGIN_NAME} \\\n -h ${MYSQL_SERVER_FULL_NAME} -P 3306 -p\n\nEnter password:\nWelcome to the MySQL monitor.  Commands end with ; or \\g.\nYour MySQL connection id is 64379\nServer version: 5.6.39.0 MySQL Community Server (GPL)\n\nCopyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.\n\nOracle is a registered trademark of Oracle Corporation and/or its\naffiliates. Other names may be trademarks of their respective\nowners.\n\nType 'help;' or '\\h' for help. Type '\\c' to clear the current input statement.\n\nmysql\u003e CREATE DATABASE airsonic;\nQuery OK, 1 row affected (0.10 sec)\n\nmysql\u003e CREATE USER 'root' IDENTIFIED BY 'airsonic';\nQuery OK, 0 rows affected (0.11 sec)\n\nmysql\u003e GRANT ALL PRIVILEGES ON airsonic.* TO 'root';\nQuery OK, 0 rows affected (1.29 sec)\n\nmysql\u003e CALL mysql.az_load_timezone();\nQuery OK, 3179 rows affected, 1 warning (6.34 sec)\n\nmysql\u003e SELECT name FROM mysql.time_zone_name;\n...\n\nmysql\u003e quit\nBye\n\n# Configure time zone\naz mysql server configuration set --name time_zone \\\n --resource-group ${RESOURCE_GROUP} \\\n --server ${MYSQL_SERVER_NAME} --value \"US/Pacific\"\n```\n\n## Bind airsonic application to MySQL database\n\nReopen an SSH connection to the Linux virtual machine:\n\n```bash\n# Log into SSH session\nssh ${ADMIN_USERNAME}@${VM_IP_ADDRESS}\n\n# In the airsonic.properties file, \n# you will need to add the following settings:\n\nsudo nano /datadrive/airsonic/airsonic.properties\n\n# add the following to the bottom of airsonic.properties\nDatabaseConfigType=jndi\nDatabaseConfigJNDIName=jdbc/airsonicDB\n\n# Then in the opt/tomcat9/conf/context.xml in the tomcat directory, \n# add the jndi config:\n\nsudo nano /opt/tomcat9/conf/context.xml\n\n```\n```xml\n\u003cResource name=\"jdbc/airsonicDB\" auth=\"Container\"\n    type=\"javax.sql.DataSource\"\n    maxActive=\"20\"\n    maxIdle=\"30\"\n    maxWait=\"10000\"\n    username=\"${MYSQL_SERVER_ADMIN_LOGIN_NAME}\"\n    password=\"${MYSQL_SERVER_ADMIN_PASSWORD}\"\n    driverClassName=\"com.mysql.jdbc.Driver\"\n    url=\"jdbc:mysql://${MYSQL_SERVER_FULL_NAME}:3306/${MYSQL_DATABASE_NAME}?useSSL=false\u0026amp;sessionVariables=sql_mode=ANSI_QUOTES\"/\u003e\n```\n```bash\n# Open the file called tomcat.service in the /etc/systemd/system\n\nsudo nano /etc/systemd/system/tomcat9.service\n\n# add few more environment properties and adjust JAVA_OPTS\n\nEnvironment=MYSQL_SERVER_NAME=\u003cyour-mysql-server-name\u003e\nEnvironment=MYSQL_SERVER_FULL_NAME=\u003cyour-mysql-server-name\u003e.mysql.database.azure.com\nEnvironment=MYSQL_SERVER_ADMIN_LOGIN_NAME=\u003cyour-admin-name\u003e@\u003cyour-mysql-server-name\u003e\nEnvironment=MYSQL_SERVER_ADMIN_PASSWORD=\u003cyour-admin-password\u003e\nEnvironment=MYSQL_DATABASE_NAME=airsonic\nEnvironment='CATALINA_OPTS=-Xms8192M -Xmx8192M -server -XX:+UseParallelGC'\nEnvironment='JAVA_OPTS=-Djava.awt.headless=true -Djava.security.egd=file:/dev/./urandom -Dairsonic.home=/datadrive/airsonic -DMYSQL_SERVER_FULL_NAME=${MYSQL_SERVER_FULL_NAME} -DMYSQL_DATABASE_NAME=${MYSQL_DATABASE_NAME} -DMYSQL_SERVER_ADMIN_LOGIN_NAME=${MYSQL_SERVER_ADMIN_LOGIN_NAME} -DMYSQL_SERVER_ADMIN_PASSWORD=${MYSQL_SERVER_ADMIN_PASSWORD}'\n\n# Reload the systemd configuration:\nsudo systemctl daemon-reload\n\n# Download MySQL Driver\n# https://dev.mysql.com/downloads/connector/j/\n\ncd /tmp\nwget https://downloads.mysql.com/archives/get/p/3/file/mysql-connector-java-5.1.48.tar.gz\n\n# extract\ntar xvzf mysql-connector-java-5.1.48.tar.gz\n\n# copy to Tomcat9/lib folder\nsudo cp mysql-connector-java-5.1.48/mysql-connector-java-5.1.48.jar /opt/tomcat9/lib\n```\n\n## Install New Relic application performance monitoring agent\n\nContinue to use the SSH connection to Linux virtual machine and install the New\nRelic application performance monitoring agent:\n```bash\n# Install New Relic agent\n# // Get New Relic JAR\ncurl -O https://download.newrelic.com/newrelic/java-agent/newrelic-agent/current/newrelic-java.zip\nsudo apt install unzip\nunzip newrelic-java.zip\n\n# Edit the New Relic configuration file\nsudo nano newrelic/newrelic.yml\n\n# Set New Relic license key and airsonic application name\n  ...\n  license_key: \u003cinsert-your-New-Relic-license-key\u003e\n  ...\n  app_name: airsonic\n\n# Copy New Relic JAR and configuration file to /opt/newrelic\nsudo mkdir /opt/newrelic\nsudo cp newrelic/newrelic.jar /opt/newrelic\nsudo cp newrelic/newrelic.yml /opt/newrelic\nsudo chgrp -R tomcat9 /opt/newrelic\n\n# Open the file called tomcat.service in the /etc/systemd/system\nsudo nano /etc/systemd/system/tomcat9.service\n\n# Add adjust Environment Variables and JAVA_OPTS\nEnvironment='JAVA_OPTS=-Djava.awt.headless=true -Djava.security.egd=file:/dev/./urandom -Dairsonic.home=/datadrive/airsonic -DMYSQL_SERVER_FULL_NAME=${MYSQL_SERVER_FULL_NAME} -DMYSQL_DATABASE_NAME=${MYSQL_DATABASE_NAME} -DMYSQL_SERVER_ADMIN_LOGIN_NAME=${MYSQL_SERVER_ADMIN_LOGIN_NAME} -DMYSQL_SERVER_ADMIN_PASSWORD=${MYSQL_SERVER_ADMIN_PASSWORD} -javaagent:/opt/newrelic/newrelic.jar'\n\n# Reload the systemd configuration:\nsudo systemctl daemon-reload\n\n# restart Tomcat 9 with airsonic running with MySQL\nsudo systemctl stop tomcat9\nsudo systemctl start tomcat9\nsudo systemctl status tomcat9\n\n# Tail logs\nsudo tail -f /opt/tomcat9/logs/catalina.out\n```\n\nYou will see the following logs to confirm airsonic application startup:\n\n```text\n           _                       _          \n     /\\   (_)                     (_)         \n    /  \\   _ _ __  ___  ___  _ __  _  ___     \n   / /\\ \\ | | '__|/ __|/ _ \\| '_ \\| |/ __|    \n  / ____ \\| | |   \\__ \\ (_) | | | | | (__     \n /_/    \\_\\_|_|   |___/\\___/|_| |_|_|\\___|    \n                                               \n                        10.6.2-RELEASE\n\n2020-12-20 20:32:14.506  INFO --- org.airsonic.player.Application          : Starting Application v10.6.2-RELEASE on tomcat-vm with PID 64604 (/opt/tomcat9/webapps/airsonic/WEB-INF/classes started by tomcat9 in /)\n2020-12-20 20:32:14.510  INFO --- org.airsonic.player.Application          : The following profiles are active: jndi\nLoading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.\n2020-12-20 20:32:22.342  INFO --- l.executor.jvm.JdbcExecutor              : SELECT COUNT(*) FROM airsonic.DATABASECHANGELOGLOCK\n2020-12-20 20:32:22.346  INFO --- l.executor.jvm.JdbcExecutor              : SELECT COUNT(*) FROM airsonic.DATABASECHANGELOGLOCK\n2020-12-20 20:32:22.374  INFO --- l.l.StandardLockService                  : Successfully acquired change log lock\n2020-12-20 20:32:25.691  INFO --- l.executor.jvm.JdbcExecutor              : SELECT MD5SUM FROM airsonic.DATABASECHANGELOG WHERE MD5SUM IS NOT NULL LIMIT 1\n2020-12-20 20:32:25.696  INFO --- l.executor.jvm.JdbcExecutor              : SELECT COUNT(*) FROM airsonic.DATABASECHANGELOG\n2020-12-20 20:32:25.697  INFO --- l.c.StandardChangeLogHistoryService      : Reading from airsonic.DATABASECHANGELOG\n2020-12-20 20:32:25.698  INFO --- l.executor.jvm.JdbcExecutor              : SELECT * FROM airsonic.DATABASECHANGELOG ORDER BY DATEEXECUTED ASC, ORDEREXECUTED ASC\n2020-12-20 20:32:25.917  INFO --- l.l.StandardLockService                  : Successfully released change log lock\n2020-12-20 20:32:25.921  INFO --- l.executor.jvm.JdbcExecutor              : SELECT COUNT(*) FROM airsonic.DATABASECHANGELOGLOCK\n2020-12-20 20:32:25.923  INFO --- l.executor.jvm.JdbcExecutor              : SELECT COUNT(*) FROM airsonic.DATABASECHANGELOGLOCK\n2020-12-20 20:32:25.925  INFO --- l.executor.jvm.JdbcExecutor              : SELECT `LOCKED` FROM airsonic.DATABASECHANGELOGLOCK WHERE ID=1\n2020-12-20 20:32:25.939  INFO --- l.l.StandardLockService                  : Successfully acquired change log lock\n2020-12-20 20:32:26.003  INFO --- l.executor.jvm.JdbcExecutor              : SELECT MD5SUM FROM airsonic.DATABASECHANGELOG WHERE MD5SUM IS NOT NULL LIMIT 1\n2020-12-20 20:32:26.004  INFO --- l.executor.jvm.JdbcExecutor              : SELECT COUNT(*) FROM airsonic.DATABASECHANGELOG\n2020-12-20 20:32:26.007  INFO --- l.c.StandardChangeLogHistoryService      : Reading from airsonic.DATABASECHANGELOG\n2020-12-20 20:32:26.008  INFO --- l.executor.jvm.JdbcExecutor              : SELECT * FROM airsonic.DATABASECHANGELOG ORDER BY DATEEXECUTED ASC, ORDEREXECUTED ASC\n2020-12-20 20:32:26.054  INFO --- l.l.StandardLockService                  : Successfully released change log lock\n2020-12-20 20:32:26.243  INFO --- o.a.p.service.SettingsService            : Java: 1.8.0_275, OS: Linux\n2020-12-20 20:32:32.014  INFO --- o.a.p.s.search.IndexManager              : Index was found (index version 18). \n2020-12-20 20:32:32.019  INFO --- o.a.p.s.MediaScannerService              : Automatic media library scanning scheduled to run every 1 day(s), starting at 2020-12-21T03:00:00.017\n2020-12-20 20:32:34.368  INFO --- o.a.p.service.PodcastService             : Automatic Podcast update scheduled to run every 1 hour(s), starting at Sun Dec 20 20:37:34 UTC 2020\n2020-12-20 20:32:37.850  INFO --- org.airsonic.player.Application          : Detected Tomcat web server\n2020-12-20 20:32:40.439  INFO --- org.airsonic.player.Application          : Started Application in 27.989 seconds (JVM running for 101.178)\n20-Dec-2020 20:32:41.241 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [/opt/tomcat9/webapps/airsonic.war] has finished in [37,219] ms\n20-Dec-2020 20:32:41.242 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/opt/tomcat9/webapps/manager]\n20-Dec-2020 20:32:42.472 INFO [main] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.\n20-Dec-2020 20:32:42.494 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/opt/tomcat9/webapps/manager] has finished in [1,252] ms\n20-Dec-2020 20:32:42.495 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/opt/tomcat9/webapps/examples]\n20-Dec-2020 20:32:44.022 INFO [main] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.\n20-Dec-2020 20:32:44.106 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/opt/tomcat9/webapps/examples] has finished in [1,611] ms\n20-Dec-2020 20:32:44.106 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/opt/tomcat9/webapps/host-manager]\n20-Dec-2020 20:32:45.423 INFO [main] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.\n20-Dec-2020 20:32:45.426 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/opt/tomcat9/webapps/host-manager] has finished in [1,320] ms\n20-Dec-2020 20:32:45.427 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/opt/tomcat9/webapps/docs]\n20-Dec-2020 20:32:46.444 INFO [main] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.\n20-Dec-2020 20:32:46.447 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/opt/tomcat9/webapps/docs] has finished in [1,020] ms\n20-Dec-2020 20:32:46.457 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler [\"http-nio-8080\"]\n20-Dec-2020 20:32:46.469 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [91313] milliseconds\n2020-12-20 20:32:47.435  INFO --- o.a.p.f.BootstrapVerificationFilter      : Servlet container: Apache Tomcat/9.0.41\n\n```\n\nThere is an open issue with the airsonic application's MySQL database schema.\nFix the schema to address the open issue. Log into the MySQL server from your \ndev machine:\n\n```bash\n# Fix the table issue https://ask.csdn.net/questions/1926148\n# from the dev machine ...\n\nmysql -u ${MYSQL_SERVER_ADMIN_LOGIN_NAME} \\\n -h ${MYSQL_SERVER_FULL_NAME} -P 3306 -p\n\nEnter password:\nWelcome to the MySQL monitor.  Commands end with ; or \\g.\nYour MySQL connection id is 64379\nServer version: 5.6.39.0 MySQL Community Server (GPL)\n\nCopyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.\n\nOracle is a registered trademark of Oracle Corporation and/or its\naffiliates. Other names may be trademarks of their respective\nowners.\n\nType 'help;' or '\\h' for help. Type '\\c' to clear the current input statement.\n\nmysql\u003e use airsonic;\nReading table information for completion of table and column names\nYou can turn off this feature to get a quicker startup with -A\n\nDatabase changed\n\nmysql\u003e ALTER TABLE podcast_episode MODIFY COLUMN description VARCHAR(4096);\n\nmysql\u003e ALTER TABLE podcast_channel MODIFY COLUMN description VARCHAR(4096);\n```\n\n## Open and configure airsonic application\n\nOpen the airsonic application from your dev machine:\n\n```bash\n# Open airsonic Web app from your dev machine\nopen http://${VM_IP_ADDRESS}:8080\n```\n\nLogin with airsonic application's default `admin` username and `admin` password. \nChange the admin password and configure the following:\n\n![](./media/airsonic-setup-media-folders.jpg) \n\n![](./media/airsonic-setup-podcast-folder.jpg)\n\n![](./media/airsonic-setup-admin-password.jpg)\n\nOpen the `Podcasts` menu and subscribe to a few podcast feeds:\n\n```text\n# +--------------------------------------------------------------------------------------+\n# | url                                                                                  |\n# +--------------------------------------------------------------------------------------+\n# | https://feeds.npr.org/510298/podcast.xml                                             |\n# | http://feeds.feedburner.com/pri/world-words                                          |\n# | http://www.cbc.ca/podcasting/includes/asithappens.xml                                |\n# | http://feeds.feedburner.com/WQXRsTheWashingtonReport                                 |\n# | http://echoes.org/podcasts/feed                                                      |\n# | https://feeds.npr.org/344098539/podcast.xml                                          |\n# | https://www.marketplace.org/feed/podcast/marketplace                                 |\n# | https://feeds.publicradio.org/public_feeds/composers-datebook/rss/rss                |\n# | https://www.marketplace.org/feed/podcast/codebreaker-by-marketplace-and-tech-insider |\n# | https://video-api.wsj.com/podcast/rss/wsj/your-money-matters                         |\n# | https://video-api.wsj.com/podcast/rss/wsj/secrets-of-wealthy-women                   |\n# | https://video-api.wsj.com/podcast/rss/wsj/tech-news-briefing                         |\n# +--------------------------------------------------------------------------------------+\n```\n\nairsonic application will start downloading podcasts and may look like:\n![](./media/airsonic-podcasts.jpg)\n\nGo to your New Relic dashboard and observe airsonic application performance:\n![](./media/new-relic-airsonic-database.png)\n![](./media/new-relic-airsonic-summary.jpg)\n\n## Contributing\n\nThis project welcomes contributions and suggestions.  Most contributions require you to agree to a\nContributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us\nthe rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.\n\nWhen you submit a pull request, a CLA bot will automatically determine whether you need to provide\na CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions\nprovided by the bot. You will only need to do this once across all repos using our CLA.\n\nThis project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).\nFor more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or\ncontact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fselvasingh%2Ftomcat-on-virtual-machine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fselvasingh%2Ftomcat-on-virtual-machine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fselvasingh%2Ftomcat-on-virtual-machine/lists"}