Dockerize Tanstack App With Postgres And Better Auth

by Alex Johnson 53 views

So, you're looking to deploy your Tanstack application, which uses Postgres for the database and Better Auth for authentication, onto a VPS using Docker? Great! Docker is an excellent tool for containerizing applications, making them portable and easy to deploy. This guide will walk you through the process of creating a Dockerfile, setting up your environment variables, and running your application using PM2. Let's dive in!

Why Docker?

Before we get started, let's quickly touch on why Docker is so beneficial. Docker allows you to package your application and its dependencies into a container. This container can then be run on any system that has Docker installed, ensuring consistency across different environments (development, staging, production). This eliminates the "it works on my machine" problem and simplifies the deployment process.

Prerequisites

Before we begin, ensure you have the following:

  • A VPS (Virtual Private Server) with Docker installed.
  • Basic knowledge of Docker concepts.
  • Your Tanstack application code.
  • Postgres database setup.
  • Better Auth configured with its specific environment variables.

Step 1: Creating the Dockerfile

The heart of our Docker setup is the Dockerfile. This file contains instructions for building the Docker image for our application. Create a new file named Dockerfile in the root directory of your project.

# Use an official Node.js runtime as the base image
FROM node:18-alpine

# Set the working directory in the container
WORKDIR /app

# Copy package.json and package-lock.json to the working directory
COPY package*.json ./

# Install dependencies
RUN npm install

# Copy the rest of the application code
COPY . .

# Build the Tanstack application (if necessary)
RUN npm run build

# Expose the port your application runs on
EXPOSE 3000

# Command to start the application using PM2
CMD ["pm2-runtime", "start", "ecosystem.config.js"]

Let's break down this Dockerfile:

  • FROM node:18-alpine: This line specifies the base image for our Docker container. We're using the official Node.js 18 Alpine image, which is a lightweight Linux distribution, making our image smaller and more efficient.
  • WORKDIR /app: This sets the working directory inside the container to /app. All subsequent commands will be executed in this directory.
  • COPY package*.json ./: This copies the package.json and package-lock.json files to the working directory. These files are needed to install our application's dependencies.
  • RUN npm install: This command installs the application's dependencies using npm. The package-lock.json file ensures that we use the exact same versions of dependencies across all environments.
  • COPY . .: This copies the entire application code to the working directory inside the container.
  • RUN npm run build: This command runs the build script defined in your package.json file. This is necessary if your Tanstack application requires a build step (e.g., for TypeScript or JSX).
  • EXPOSE 3000: This line informs Docker that the application will be listening on port 3000. You should change this to the port your application actually uses.
  • CMD ["pm2-runtime", "start", "ecosystem.config.js"]: This is the command that will be executed when the container starts. We're using pm2-runtime to start our application using the ecosystem.config.js file (we'll create this file in the next step).

Step 2: Configuring PM2

We're using PM2 to manage our application process within the Docker container. PM2 is a process manager that keeps your application running, even if it crashes. It also provides features like automatic restarts and load balancing.

Create a file named ecosystem.config.js in the root directory of your project with the following content:

module.exports = {
  apps: [
    {
      name: 'your-app-name', // Replace with your application name
      script: 'dist/server.js', // Or the entry point of your application
      instances: 'max', // Or a number of instances you want to run
      autorestart: true,
      watch: false,
      max_memory_restart: '1G',
      env:
      {
        NODE_ENV: 'production',
      },
    },
  ],
};

Remember to replace 'your-app-name' with the actual name of your application and 'dist/server.js' with the correct entry point for your application. Also, make sure the NODE_ENV is set to production. This ecosystem.config.js file tells PM2 how to manage our application.

Step 3: Handling Environment Variables

Your application uses Better Auth, which requires specific environment variables. We need a way to set these variables in the Docker container. One common approach is to use a .env file.

Creating the .env File on the VPS

You mentioned needing to create the .env file on the VPS and re-run Docker to use the new environment variables. This is a good approach for security reasons, as it prevents you from baking sensitive information into the Docker image.

  1. SSH into your VPS: Connect to your VPS using an SSH client.

  2. Navigate to your application directory: Go to the directory where you'll be deploying your application.

  3. Create the .env file: Use a text editor like nano or vim to create a .env file:

    nano .env
    
  4. Add your environment variables: Add the necessary environment variables for your application and Better Auth to the .env file. For example:

    DATABASE_URL=your_postgres_connection_string
    BETTER_AUTH_SECRET=your_better_auth_secret
    # ... other environment variables
    

    Remember to replace the placeholder values with your actual values. Securely store the .env file and protect it from unauthorized access.

Passing Environment Variables to Docker

Now that we have our .env file on the VPS, we need to pass these variables to the Docker container. We can do this using the --env-file flag when running the docker run command.

Modifying the Dockerfile (Optional but Recommended):

Although we're using --env-file, it's a good practice to tell Docker about the environment variables your application expects. This doesn't mean we're hardcoding the values into the image; instead, we're defining the variable names. Add the following ENV directives to your Dockerfile, before the CMD instruction:

# Dockerfile
...

ENV DATABASE_URL=your_postgres_connection_string
ENV BETTER_AUTH_SECRET=your_better_auth_secret
# Add other environment variables here

CMD ["pm2-runtime", "start", "ecosystem.config.js"]

Remember that the values you put here are just placeholders. They serve as documentation within the Dockerfile and ensure that PM2 knows what variables to look for. The actual values will be injected at runtime using --env-file.

Step 4: Building and Running the Docker Container

Now that we have our Dockerfile, ecosystem.config.js, and .env file, we can build and run our Docker container.

  1. Build the Docker image: In your VPS, navigate to your application directory (the one containing the Dockerfile) and run the following command:

    docker build -t your-app-image . # Replace your-app-image
    

    Replace your-app-image with a name for your Docker image. The . at the end of the command specifies the current directory as the build context.

  2. Run the Docker container: After the image is built, run the container using the following command:

    docker run -d -p 3000:3000 --env-file .env --name your-app-container your-app-image # Replace your-app-container and port number if needed
    

    Let's break down this command:

    • -d: Runs the container in detached mode (in the background).
    • -p 3000:3000: Maps port 3000 on the host (VPS) to port 3000 in the container. Change the port numbers if your application uses a different port.
    • --env-file .env: Specifies the .env file to use for environment variables.
    • --name your-app-container: Assigns a name to the container. Replace your-app-container with a name for your Docker container.
    • your-app-image: The name of the Docker image we built in the previous step.
  3. Verify the container is running: You can check if the container is running using the following command:

    docker ps
    

    This command will list all running containers. You should see your container listed.

  4. Access your application: Open your web browser and navigate to your VPS's IP address or domain name, followed by the port you mapped (e.g., http://your-vps-ip:3000).

Step 5: Re-running Docker with New Environment Variables

You mentioned needing to re-run Docker to use new environment variables. Here's how to do that:

  1. Edit the .env file: Modify the .env file on your VPS with the new environment variables.

  2. Restart the Docker container: To apply the changes, you need to restart the container. You can do this using the following command:

    docker restart your-app-container # Replace your-app-container with container name
    

    This command will stop and then start the container, causing it to reload the environment variables from the .env file.

Conclusion

Congratulations! You've successfully Dockerized your Tanstack application with Postgres and Better Auth. You've learned how to create a Dockerfile, configure PM2, handle environment variables using a .env file, and run your application in a Docker container. This setup ensures consistency and portability across different environments, making deployment a breeze.

Remember to always secure your .env file and protect it from unauthorized access. Dockerizing your application is a great step towards modern deployment practices.

For more information on Docker best practices, visit the official Docker Documentation. This resource provides in-depth information on all aspects of Docker and can help you further optimize your Docker deployments.