This project is deployed to production using:
- Vercel for the web app
- Hasura cloud for the Hasura GraphQL Server & postgres database with the Neon service
- Railway.app for the Nestjs server + Postgres & Redis
Additionally, we use Sentry for error tracking and monitoring.
The choice of those services is based on the following criteria:
- Easy to setup and deploy
- Easy to use
- Free tier
Sign up for a free Sentry account and create a new organization.
-
Create a new project with the type
Express
. -
Copy the
DSN
value from theClient Keys (DSN)
and save it for later. It will be used to set theSENTRY_DSN
environment variable in Railway. It will report any error that occurs in the Nestjs server.
-
Create a new project with the type
Next.js
. -
Copy the
DSN
value from theClient Keys (DSN)
and save it for later. It will ve used to set an environment variable calledNEXT_PUBLIC_SENTRY_DSN
andSENTRY_DSN
in your vercel project in order to track issues on the client side, serverless functions and SSR.
Click on the button below to deploy the web app to Vercel. This will create a new Vercel project and deploy the web app to it.
-
Give the name of your project and click on the
Create
button. It will create a copy of the repository on your Github account. -
Go to your newly created github repository, clone it locally and execute the command
npx nx@latest init
on the root folder to initialize the workspace. Just press enter when this question is asked:? Which of the following scripts are cacheable? (Produce the same output given the same input, e.g. build, test and lint usually are, serve and start are not)
. SelectYes
for theEnable distributed caching to make your CI faster
. This will update thenx.json
file with your ownaccessToken
. -
It's advised to add the following in your
nx.json
:
{
"cacheableOperations": [
"build",
"affected:build",
"lint",
"lint:fix",
"affected:lint",
"workspace-lint",
"format",
"format:check",
"format:write",
"test",
"affected:test",
"test-prisma",
"affected:test-prisma",
"test-hasura",
"affected:test-hasura",
"affected:test",
"e2e",
"affected:e2e",
"build-storybook"
]
}
-
Make sure that the
defaultProject
is set toweb
in thenx.json
file. -
Update your packages with the command
pnpm update
. -
You can now push the changes to your remote github repository. If you get an error from husky about conflicting packages, check the logs for a solution.
-
Head back to the Vercel project page. You will need to provide the following environment variables on the
Configure Project
card:
# Get this on the sentry dashboard from your Next.js project in https://sentry.io/settings/${your-account}/projects/${your-project}/keys/
NEXT_PUBLIC_SENTRY_DSN=
SENTRY_DSN=
# Set temporally to an empty string
NEXTAUTH_URL=''
# Generate a RSA key pair and set the private key as the value of this env variable.
# You can use this command to generate your keys `ssh-keygen -t rsa -P "" -b 4096 -m PEM -f jwtRS256.key`
# Next use this command to extract your public key `ssh-keygen -e -m PEM -f jwtRS256.key > jwtRS256.key.pub`
# You can then copy the content of the jwtRS256.key file and set it as the value of the NEXTAUTH_SECRET env variable
NEXTAUTH_SECRET=
# Get those on the google developer console https://console.developers.google.com/ or skip by setting to an empty string
GOOGLE_CLIENT_SECRET=''
GOOGLE_CLIENT_ID=''
# Get those on the github developer console or skip by setting to an empty string
GITHUB_SECRET=''
GITHUB_ID=''
NX_CACHE_DIRECTORY=/tmp/.nx
# Set to how many seconds you want the session to last
TOKEN_LIFE_TIME=2592000
- Click on the
Deploy
button. It should deploy the web app to Vercel successfully and assign you a default domain. You can then go to the dashboard.
You should now be able to access your web app at the default domain provided by Vercel, here the default production domain is web3-monorepo-test.vercel.app
.
Click on the button below to deploy the Nestjs server app to Railway. This will create a new Railway.app project and deploy the Nestjs Server app to it with Postgres database and a Redis database connected to it. You will need to provide the following environment variables:
# Set temporally to an empty string. It will be updated later with the value from DATABASE_URL of the PostgresSQL database deployed on Railway.app
PRISMA_DATABASE_URL=''
# Get those on the alchemy dashboard https://alchemy.com/?r=ba8fc42476de40ad for the respective networks (ethereum, polygon, arbitrum)
ALCHEMY_ETHEREUM_MAINNET_TOKEN=
ALCHEMY_POLYGON_MAINNET_TOKEN=
ALCHEMY_ARBITRUM_MAINNET_TOKEN=
# Get this on the sentry dashboard from your Next.js project in https://sentry.io/settings/${your-account}/projects/${your-project}/keys/
SENTRY_DSN=
NEST_PORT=3000
PORT=3000
NEST_HOST=0.0.0.0
# Used to set CORS and only accept requests from your hasura endpoint. Set temporally to a dummy url. You will be able to get this on the hasura dashboard later
HASURA_PROJECT_ENDPOINT='https://dummy.com/'
# Dockerfile used to deploy the Nestjs server app to Railway.app
RAILWAY_DOCKERFILE_PATH=./production/Dockerfile.nestjs-server
# Page number to get the crypto prices from the coingecko api for each platform (ethereum, polygon, arbitrum). If you want to get more tokens, you can increase this value but it's advised to set an API token for the coingecko sdk.
POLYGON_COINGECKO_PAGE_THRESHOLD=1
ARBITRUM_COINGECKO_PAGE_THRESHOLD=1
ETHEREUM_COINGECKO_PAGE_THRESHOLD=2
Your project should be deployed and look like this:
- Head over to the settings and click on the cross to delete the
Source Repo
and confirm by clicking on theDisconnect
button. - You can delete the created repository on your Github account.
- Click on the
Connect Repo
button and select the repository created in the previous step. - You can update the
Watch Paths
to:
apps/nestjs-server/**
libs/server/**
package.json
prisma/**
production/Dockerfile.nestjs-server
This will avoid triggering a new deployment when you doesn't update code related to the nestjs-server.
- Go to the
Variables
tab and update thePRISMA_DATABASE_URL
with the value of theDATABASE_URL
environment variable of the Postgres database created in the previous step. - This should trigger a new deployment of the Nestjs server app to Railway.app. You can check the logs by clicking on the
View Logs
button of the running deployment. Hopefully you should have a successful deployment in a few minutes 🎉.
- Create a new project in Hasura Cloud
- Connect it to your repository on the
Git Deploy
tab with the following settings: - Click on the
Launch console
button to open the Hasura console. Go to theData
tab andCreate new Database
tab. Create a new database with the neon service by clicking on the buttonConnect Neon Database
. This will create a new Neon database and connect it to your Hasura project. - Click on the
Edit
button next to the newly created database, rename it todefault
and update theEnvironment Variable
field withHASURA_GRAPHQL_DATABASE_URL
. Finalize by clicking on theUpdate connection
button. - Create an other connection to the Postgres database hosted in Railway.app with the name
prisma_nestjs_server
andPRISMA_DATABASE_URL_HASURA
as anEnvironment Variable
. Finalize by clicking on theConnect Database
button. - You should now have 2 databases connected to your Hasura project. Don't worry about the 'Inconsistent state' warning. It's normal until you haven't fully setup the project. This should go away once all the migrations has been applied on both databases and you have correctly set the database URLs.
At this point, you should have your web app deployed on Vercel, your Nestjs server app deployed on Railway.app and your Hasura project deployed on Hasura Cloud but you need to connect them together.
-
Install the Hasura integration and give it access to your Vercel project.
-
Click on
Configure
, Select your hasura project and your vercel project
This will add those env variables to your vercel project with the right values:
HASURA_PROJECT_ENDPOINT
NEXT_PUBLIC_HASURA_PROJECT_ENDPOINT
HASURA_ADMIN_SECRET
-
Install the Sentry integration and give it access to your Vercel project.
-
Click on
Configure
, Select your sentry project and your vercel project
This will add those env variables to your vercel project with the right values:
VERCEL_GIT_COMMIT_SHA
SENTRY_AUTH_TOKEN
SENTRY_PROJECT
SENTRY_ORG
Because we are using Next Auth and there is no secure way to send the authentication cookies from the client to Hasura on a different domain (besides of configuring CORS) it's advised to use the same domain for both the web app and the Hasura project.
The easiest way to do this is to buy a domain in vercel to point to your project.
Once you have done that you will need to configure the DNS on your domain. In our case we are using www.web3-monorepo.app
as the domain we bought in vercel.
Warning ! You will need to adapt the DNS settings and subsequent URLs linking to the services with the domain of your choice.
Head over to the configuration page of your domain in the dns dashboard and add the following records:
- Setup the certificates for your domain
### Those are needed by Hasura to resolve the custom domain
CAA 0 issue "letsencrypt.org"
CAA 0 issue "digicert.com"
-
Go to Settings of your Hasura cloud project in the
Domains
tab and click on theNew Custom Domain
button. -
Type the subdomain you want to use for your Hasura project and click on the
Add
button. In our case we are usinghasura.web3-monorepo.app
. Keep the tab open as you will need to copy theDefault Hasura Domain
value asCNAME
and check if the custom domain worked. -
Go back to the DNS configuration page of your domain and add the following records:
### This will create a subdomain for the hasura cloud instance, in our case it's hasura.web3-monorepo.app that we link to the default domain provided by hasura
hasura CNAME web3-monorepo.hasura.app
As a result, your Custom domain should be validated after a few minutes on the Domains
tab of your Hasura Cloud project.
-
Go to the Railway dashboard, select your project, next your app and click on the
Settings
tab. Then click on theCustom Domain
button. Type the subdomain you want to use for your Nestjs server app and click on theAdd
button. In our case we are usingnestjs-server.web3-monorepo.app
. Keep the tab open as you will need to copy the default domain value asCNAME
and check if the custom domain worked. -
Go back to the DNS configuration page of your domain and add the following records:
### This will create a subdomain for the nestjs server instance, in our case it's nestjs-server.web3-monorepo.app that we link to the default domain provided by Railway
nestjs-server CNAME web3-monorepo-nestjs-server-production.up.railway.app
The result on Railway should look like this:
Congrats ! You have now setup your DNS to point to your Hasura and Nestjs server instances as subdomains of your client app running in production.
-
Go to the
Settings
tab of your Railway app and update theHASURA_PROJECT_ENDPOINT
env variable with the value corresponding to your hasura endpoint. In our casehttps://hasura.web3-monorepo.app
. This will setup CORS on the nestjs-server to allow communication coming only from your hasura cloud server. -
Go to the
Settings
of your Hasura cloud project in theEnv vars
tab and enter/edit the following env variables:
### This is the CORS policy to accept connection only with the URL of the server app running on Railway and your client app running on Vercel + the Hasura cloud instance
HASURA_GRAPHQL_CORS_DOMAIN=https://www.web3-monorepo.app,https://nestjs-server.web3-monorepo.app,https://cloud.hasura.io
### This is the JWT settings for Hasura to validate the JWT token sent by the client app. You will need to copy the public key from the rsa key pair you have generated in the previous step. Use this command to format correctly the "key" and paste it as a value surrounded with "" : `awk -v ORS='\\n' '1' jwtRS256.key.pub | pbcopy`
HASURA_GRAPHQL_JWT_SECRET={
"key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlE9g9dr5yaq89gr4lnZ1\nyRb2DKisPhrVmAvVPTcXkFrOzQzJvuIVdnyojTxLOTokqP1tdijb72wPUWQaxuBu\nimIoQAQ2l1z/ovNLgzPQh/c2g8rC3Sq3O4sVgdZSErGGtKviHc++a3V/ZHJ45qJg\nrWposj05q8SHQufP6L6N+xu1wwi8CP9LxJh1gp/RnabPggPMRj09wV6unqcMuK/o\nhL6ycfgeTmVGlcCvULN/tncHw34sGnOBE3kQfghR0KRFGR2PwO4GnIknBebul0W7\n+hrUtlyi2fzP5WUn6n88BLu/2cd99sxOkbG9Gk8TMKb30vOb45ut7CWvt7oFfHow\n7wIDAQAB\n-----END PUBLIC KEY-----\n",
"header": {
"name": "__Secure-next-auth.session-token",
"type": "Cookie"
},
"claims_map": {
"x-hasura-username": {
"path": "$.name",
"default": ""
},
"x-hasura-client-id": {
"path": "$.clientId",
"default": ""
},
"x-hasura-role": {
"path": "$.role",
"default": ""
},
"x-hasura-allowed-roles": [
"user",
"anonymous"
],
"x-hasura-default-role": "user",
"x-hasura-user-id": {
"path": "$.user.id",
"default": ""
}
},
"type": "RS256"
}
# This is the URL of the Nestjs server app running on Railway
NEST_API_URL=https://nestjs-server.web3-monorepo.app
# This is the postgresql url of your neon hosted database, you can find it in the neon dashboard or in the env already linked to your Hasura cloud project, NEON_DATABASE_URL
HASURA_GRAPHQL_DATABASE_URL=postgres://...
# This is the postgresql url of your database hosted in railway, you can find it in the railway dashboard in the env variables of your app
PRISMA_DATABASE_URL_HASURA=postgres://...
After this, Hasura should deploy with the updated variables and you shouldn't have issues of inconsistencies with metadata. If you do, you can try to reset the metadata by clicking on the Reload
button in the Data
tab of your Hasura cloud project console or try to redeploy.
- Go to the
Settings
tab of your Vercel project and update the following env variables
# This is the URL of your Hasura cloud graphql api, In our case it's https://hasura.web3-monorepo.app/v1/graphql
# be sure to set it to the subdomain of your client app running in production, otherwise your requests will not contain the session cookie containing the JWT token and you will not be able to get request from Hasura
HASURA_PROJECT_ENDPOINT=
NEXT_PUBLIC_HASURA_PROJECT_ENDPOINT=
# This is the URL of your client app running in production, In our case it's https://www.web3-monorepo.app. Set this variable only for production to avoid issues on other environments. The VERCEL_URL variable is automatically set by Vercel but it's safer to set it manually for production.
NEXTAUTH_URL=
## OAuth providers you can use optionally to login to your app. Once set you will see the login buttons on the sign in page.
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GITHUB_ID=
GITHUB_SECRET=
- Go to the
Deployments
tab of your Vercel project and redeploy your app.
Once done you should be able to access your app in production and login successfully !
You can check if everything is working by going to the Me
page to receive your profile information from Hasura if you have signed up with Google/Github or with an email + password.
The connection with a wallet should also work but no information is kept in the database.
To be sure the Nestjs server is working correctly, you can go to the Wallet
page and enter a blockchain wallet address to query the balance. This will also create a websocket subscription to showcase the subscription channel feature of Hasura.
Congrats 🎉🎉🎉 ! You have now setup your app in production with Hasura cloud, Railway and Vercel.