Skip to main content
Glama
build-deb.sh10.4 kB
#!/usr/bin/env bash # Fail on error set -e # Echo commands set -x # Check if dpkg-deb is available if ! command -v dpkg-deb >/dev/null 2>&1; then echo "dpkg-deb could not be found" echo "Please install dpkg-deb before running this script" exit 1 fi # Service variables # These represent the required directories and files for the service SERVICE_NAME="medplum" TMP_DIR="medplum-deb" LIB_DIR="$TMP_DIR/usr/lib/$SERVICE_NAME" ETC_DIR="$TMP_DIR/etc/$SERVICE_NAME" VAR_DIR="$TMP_DIR/var/lib/$SERVICE_NAME" SYSTEM_DIR="$TMP_DIR/lib/systemd/system" DEBIAN_DIR="$TMP_DIR/DEBIAN" NGINX_SITES_AVAILABLE_DIR="$TMP_DIR/etc/nginx/sites-available" # Placeholder values for app build # These are same placeholder values used in `.github/build.yml` MEDPLUM_BASE_URL="__MEDPLUM_BASE_URL__" MEDPLUM_CLIENT_ID="__MEDPLUM_CLIENT_ID__" MEDPLUM_REGISTER_ENABLED="__MEDPLUM_REGISTER_ENABLED__" MEDPLUM_AWS_TEXTRACT_ENABLED="__MEDPLUM_AWS_TEXTRACT_ENABLED__" GOOGLE_CLIENT_ID="__GOOGLE_CLIENT_ID__" RECAPTCHA_SITE_KEY="__RECAPTCHA_SITE_KEY__" # Get version VERSION=$(node -p "require('./package.json').version") echo "Building version $VERSION" # Clear previous builds rm -rf "$TMP_DIR" rm -rf "$SERVICE_NAME-$VERSION.deb" # Copy package files PACKAGES=("app" "ccda" "core" "definitions" "fhirtypes" "fhir-router" "react" "react-hooks" "server") for package in ${PACKAGES[@]}; do echo "Copy $package" mkdir -p "$LIB_DIR/packages/$package" cp "packages/$package/package.json" "$LIB_DIR/packages/$package" cp -r "packages/$package/dist" "$LIB_DIR/packages/$package" done # Copy root package.json cp package.json "$LIB_DIR" cp package-lock.json "$LIB_DIR" # Create the server config mkdir -p "$ETC_DIR" cp packages/server/medplum.config.json "$ETC_DIR" sed -i "s|file:./binary/|file:/var/lib/$SERVICE_NAME/binary/|g" "$ETC_DIR/medplum.config.json" # Create the data directory mkdir -p "$VAR_DIR/binary" echo "Medplum data files" > "$VAR_DIR/README.txt" # Move into the working directory pushd "$LIB_DIR" # Install dependencies npm ci --omit=dev --omit=optional --omit=peer # Move back to the original directory popd # Create the systemd service definition mkdir -p "$SYSTEM_DIR" # Create the service file cat > "$SYSTEM_DIR/$SERVICE_NAME.service" <<EOF [Unit] Description=Medplum After=network.target [Service] ExecStart=/usr/bin/node /usr/lib/$SERVICE_NAME/packages/server/dist/index.js "file:/etc/$SERVICE_NAME/medplum.config.json" Restart=always User=$SERVICE_NAME Group=$SERVICE_NAME Environment=PATH=/usr/bin:/usr/local/bin Environment=NODE_ENV=production WorkingDirectory=/usr/lib/$SERVICE_NAME [Install] WantedBy=multi-user.target EOF # Create the nginx sites-available directory mkdir -p "$NGINX_SITES_AVAILABLE_DIR" # Create the app site configuration cat > "$NGINX_SITES_AVAILABLE_DIR/medplum-app" <<EOF server { listen 80; listen [::]:80; server_name app.example.com; # Redirect HTTP to HTTPS location / { return 301 https://\$server_name\$request_uri; } } server { listen 443 ssl; listen [::]:443 ssl; server_name app.example.com; ssl_certificate /etc/letsencrypt/live/app.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/app.example.com/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # React app built files location root /usr/lib/medplum/packages/app/dist; index index.html; # Gzip compression gzip on; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; # Main location block location / { try_files \$uri \$uri/ /index.html; } # HTML files should not be cached (for SPA routing) location ~* \.html$ { add_header Cache-Control "no-cache, no-store, must-revalidate"; expires 0; } # All other files can be cached (they have content-based hashes) location ~* \.(?!html$) { expires 1y; add_header Cache-Control "public, no-transform"; } } EOF # Create the server site configuration cat > "$NGINX_SITES_AVAILABLE_DIR/medplum-server" <<EOF server { listen 80; listen [::]:80; server_name api.example.com; # Redirect HTTP to HTTPS location / { return 301 https://\$server_name\$request_uri; } } server { listen 443 ssl; listen [::]:443 ssl; server_name api.example.com; ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; location / { proxy_pass http://localhost:8103; proxy_http_version 1.1; proxy_set_header Upgrade \$http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host \$host; proxy_cache_bypass \$http_upgrade; proxy_set_header X-Real-IP \$remote_addr; proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto \$scheme; } } EOF # Create Debian files mkdir -p "$DEBIAN_DIR" # Create the Debian template variables cat > "$DEBIAN_DIR/templates" <<EOF Template: medplum/server_hostname Type: string Default: api.example.com Description: API Server Hostname Enter the hostname where the Medplum API server will be accessible. Template: medplum/app_hostname Type: string Default: app.example.com Description: Web Application Hostname Enter the hostname where the Medplum web application will be accessible. Template: medplum/db_host Type: string Default: localhost Description: Database Host Enter the PostgreSQL server hostname. Leave as localhost if the database is on this machine. Template: medplum/db_password Type: password Description: Database Password Choose a password for the Medplum database user. This will be used to create the initial database user. EOF # Create the Debian config script # This file will be executed by debconf to ask the user for configuration values cat > "$DEBIAN_DIR/config" <<EOF #!/bin/sh set -e # Source debconf library . /usr/share/debconf/confmodule # Ask the questions db_input high medplum/server_hostname || true db_input high medplum/app_hostname || true db_input medium medplum/db_host || true if db_get medplum/db_host && [ "\$RET" != "localhost" ]; then db_input high medplum/db_password || true fi db_go || true EOF # Create the Debian control file # "Depends" is a list of packages that must be installed # "Recommends" is a list of packages that are recommended, and will be installed by default # "Suggests" is a list of packages that are suggested, but not installed by default cat > "$DEBIAN_DIR/control" <<EOF Package: $SERVICE_NAME Version: $VERSION Section: base Priority: optional Architecture: all Depends: debconf, nodejs Recommends: nginx, postgresql-16, redis-server Suggests: certbot Maintainer: Medplum <hello@medplum.com> Description: Medplum Server EOF # Create the Debian post-install script cat > "$DEBIAN_DIR/postinst" <<EOF #!/bin/sh set -e # Source debconf library . /usr/share/debconf/confmodule # Get the configured values db_get medplum/server_hostname SERVER_HOSTNAME="\$RET" db_get medplum/app_hostname APP_HOSTNAME="\$RET" db_get medplum/db_host DB_HOST="\$RET" db_get medplum/db_password DB_PASSWORD="\$RET" # Update the app config # Recursively apply to all text files in the app dist directory find "/usr/lib/medplum/packages/app/dist" -type f -exec sed -i \ -e "s|__MEDPLUM_BASE_URL__|https://\${SERVER_HOSTNAME}/|g" \ -e "s|__MEDPLUM_CLIENT_ID__|\${MEDPLUM_CLIENT_ID}|g" \ -e "s|__GOOGLE_CLIENT_ID__|\${GOOGLE_CLIENT_ID}|g" \ -e "s|__RECAPTCHA_SITE_KEY__|\${RECAPTCHA_SITE_KEY}|g" \ -e "s|__MEDPLUM_REGISTER_ENABLED__|\${MEDPLUM_REGISTER_ENABLED}|g" \ {} \; # Update the server config if [ -f /etc/medplum/medplum.config.json ]; then # Update baseUrl sed -i "s|\"baseUrl\":[[:space:]]*\"[^\"]*\"|\"baseUrl\": \"https://\$SERVER_HOSTNAME/\"|" /etc/medplum/medplum.config.json # Update appBaseUrl sed -i "s|\"appBaseUrl\":[[:space:]]*\"[^\"]*\"|\"appBaseUrl\": \"https://\$APP_HOSTNAME/\"|" /etc/medplum/medplum.config.json fi # Update nginx configurations if they exist if [ -f /etc/nginx/sites-available/medplum-server ]; then sed -i "s|api\.example\.com|\$SERVER_HOSTNAME|g" /etc/nginx/sites-available/medplum-server sed -i "s|app\.example\.com|\$APP_HOSTNAME|g" /etc/nginx/sites-available/medplum-server fi if [ -f /etc/nginx/sites-available/medplum-app ]; then sed -i "s|api\.example\.com|\$SERVER_HOSTNAME|g" /etc/nginx/sites-available/medplum-app sed -i "s|app\.example\.com|\$APP_HOSTNAME|g" /etc/nginx/sites-available/medplum-app fi # Create the Medplum user addgroup --system $SERVICE_NAME adduser --system --ingroup $SERVICE_NAME $SERVICE_NAME chown $SERVICE_NAME:$SERVICE_NAME "/var/lib/$SERVICE_NAME" # Start or restart the service if [ "\$1" = "configure" ]; then systemctl daemon-reload systemctl enable $SERVICE_NAME.service if [ -n "\$2" ]; then # Restart the service if this is an upgrade systemctl restart $SERVICE_NAME else # Start the service if this is a fresh install systemctl start $SERVICE_NAME fi fi EOF # Create the Debian pre-remove script cat > "$DEBIAN_DIR/prerm" <<EOF #!/bin/sh set -e # Only fully stop/disable on package removal if [ "\$1" = "remove" ]; then systemctl stop $SERVICE_NAME.service systemctl disable $SERVICE_NAME.service fi # For upgrades, we only need to stop the service temporarily if [ "\$1" = "upgrade" ]; then systemctl stop $SERVICE_NAME.service fi EOF # Set permissions chmod 755 "$DEBIAN_DIR/config" chmod 755 "$DEBIAN_DIR/postinst" chmod 755 "$DEBIAN_DIR/prerm" # Build the package # Use the standard Debian package naming convention: <name>_<version>_<architecture>.deb # We can use architecture "all" because we are not building a binary package DEB_FILENAME="${SERVICE_NAME}_${VERSION}_all.deb" dpkg-deb --build --root-owner-group -Zgzip "$TMP_DIR" "$DEB_FILENAME" # Generate the checksum CHECKSUM_FILENAME="$DEB_FILENAME.sha256" sha256sum "$DEB_FILENAME" > "$CHECKSUM_FILENAME" # Check the checksum sha256sum --check "$CHECKSUM_FILENAME" # Cleanup temp files rm -rf "$TMP_DIR" # Done echo "Done"

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/medplum/medplum'

If you have feedback or need assistance with the MCP directory API, please join our Discord server