# Virtual Machine (Docker)

Deploy FormSG to a virtual machine for small-scale production use, staging environments, or pilot deployments. This guide uses Docker Compose on a single server to get FormSG running with minimal infrastructure complexity.

### Overview

This deployment is ideal for:

* **Pilot projects** - Test FormSG with real users before full production
* **Small organizations** - Up to 1,000 form submissions per month
* **Staging environments** - Test customizations and integrations
* **Air-gapped deployments** - Isolated government networks
* **Budget-conscious teams** - Simple infrastructure with predictable costs

### Prerequisites

* Cloud provider account (AWS, Azure, GCP) or physical server access
* Basic Linux command line knowledge
* SSH client on your local machine
* Domain name (optional but recommended)

### Architecture Overview

<figure><img src="https://3225095994-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFiAVh1Ff3KUiYxMAZuJG%2Fuploads%2FsCNmoCABlx9kYtFUc3UG%2Fimage.png?alt=media&#x26;token=d9ebf561-8a54-44c9-b2df-bfa7e6fae50c" alt=""><figcaption></figcaption></figure>

This VM deployment runs FormSG components on a single server using docker containers, specific services can be seen in docker config [here](https://github.com/opengovsg/FormSG/blob/develop/docker-compose.yml).

### Deployment Steps

{% stepper %}
{% step %}

#### Create Virtual Machine

**Cloud Provider Setup:**

Choose your preferred cloud provider and create a new VM instance:

* **AWS**: EC2 → Launch Instance → Ubuntu 22.04 LTS
* **Azure**: Virtual Machines → Create → Ubuntu 22.04 LTS
* **GCP**: Compute Engine → VM instances → Create → Ubuntu 22.04 LTS

**Recommended Specifications:**

* **CPU**: 2 vCPUs (minimum 1 vCPU for testing)
* **Memory**: 4 GB RAM (minimum 2 GB)
* **Storage**: Few GBs, depending on need
* **Network**: Public IP address if external access needed

**Instance Examples:**

* **AWS**: t3.small or t3.medium (t2.micro for testing)
* **Azure**: Standard\_B2s or Standard\_B1ms (Standard\_B1s for testing)
* **GCP**: e2-small or e2-medium (e2-micro for testing)

**Security Group/Firewall Rules:**

* SSH (port 22) from your IP address
* HTTP (port 80) from anywhere (if using domain)
* HTTPS (port 443) from anywhere (if using SSL)
* Custom port 5173 from anywhere (for direct access)

{% hint style="warning" %}
**Security Note**: Restrict SSH access to your IP address only. Consider using a VPN or bastion host for production deployments.
{% endhint %}
{% endstep %}

{% step %}

#### Connect to Your VM

SSH into your newly created virtual machine:

```bash
# Replace with your VM's public IP address
ssh ubuntu@YOUR_VM_IP_ADDRESS

# If using SSH key authentication (recommended)
ssh -i /path/to/your-key.pem ubuntu@YOUR_VM_IP_ADDRESS
```

**First Time Setup:**

```bash
# Update system packages
sudo apt update && sudo apt upgrade -y

# Install essential tools (adjust based on your VM setup)
sudo apt install -y curl wget git htop unzip
```

{% hint style="info" %}
**Additional tools**: Depending on your VM setup, you may want to install other utilities like `wget`, `htop`, `unzip`, `nano`, or `vim`. Install what you need for your environment.
{% endhint %}
{% endstep %}

{% step %}

#### Install Docker and Docker Compose

This deployment path requires Docker and Docker Compose to run. Install them using your preferred method:

**Option 1: Official Docker Installation (Recommended)**

Follow the official Docker installation guide for Ubuntu:

* Visit: <https://docs.docker.com/engine/install/ubuntu/>
* Ensure you install Docker Compose plugin

**Option 2: Quick Installation via Convenience Script**

```bash
# Download and run Docker's convenience script
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

# Install Docker Compose plugin
sudo apt-get update
sudo apt-get install docker-compose-plugin
```

**Option 3: Package Manager Installation**

```bash
# Install Docker from Ubuntu repositories (may be older version)
sudo apt update
sudo apt install docker.io docker-compose-v2
```

**Post-Installation Setup:**

```bash
# Add your user to docker group (avoids using sudo)
sudo usermod -aG docker $USER

# Apply group changes
newgrp docker

# Verify installation
docker --version
docker compose version
docker run hello-world
```

{% hint style="info" %}
**Note**: You may need to log out and back in for group changes to take effect. The convenience script (Option 2) is often the easiest for most usecase.
{% endhint %}
{% endstep %}

{% step %}

#### Clone FormSG Repository

Get the FormSG source code:

```bash
# Clone FormSG repository
git clone https://github.com/opengovsg/FormSG.git
cd FormSG

# Install Node.js (using NodeSource repository)
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt-get install -y nodejs

# Verify Node.js version
node --version  # Should show v22.x.x
```

{% endstep %}

{% step %}

#### Configure Environment

Set up FormSG configuration for your VM:

```bash
# Copy example environment file
cp .env.example .env

# Edit environment file
nano .env
```

**Essential Configuration Changes:**

Update these variables in your `.env` file:

```bash
# Email Configuration (required for OTP login)
# Option 1: Use a simple SMTP service
SES_HOST=smtp.gmail.com
SES_PORT=587
SES_USER=your-email@gmail.com
SES_PASS=your-app-password
MAIL_FROM=noreply@your-domain.com

# Option 2: Use your organization's SMTP
SES_HOST=mail.yourorg.gov
SES_PORT=587
SES_USER=formsg-service
SES_PASS=your-smtp-password
MAIL_FROM=formsg@yourorg.gov


# Database (MongoDB will run in Docker)
DB_HOST=mongodb://mongo:27017/formsg
```

{% endstep %}

{% step %}

#### Install Dependencies and Build

Install FormSG dependencies:

```bash
# Install npm packages
npm install && npm --prefix serverless/virus-scanner install

# Build frontend for production
npm run build:frontend

# Verify build completed
ls -la dist/frontend
```

This step may take 5-10 minutes depending on your VM's specs and network speed.
{% endstep %}

{% step %}

#### Start FormSG Services

You have two options for starting FormSG:

**Option 1: All-in-One (Recommended)**

```bash
# Starts both frontend and backend services (via docker) together
npm run dev
```

This handles both the frontend build and Docker services automatically.

**Option 2: Backend Only**

```bash
# Start backend services only
docker compose up -d

# Then start frontend separately (in another terminal/tmux ession)
npm run dev:frontend
```

Use this if you want more control over individual services.

**Services Starting:**

* **MongoDB**: Database server
* **MailDev**: Email testing
* **FormSG Backend**: API server
* **FormSG Frontend**: Web interface (port 5173)

{% hint style="info" %}
**Recommended**: Use `npm run dev` for simplicity. It handles everything you need for a VM deployment.
{% endhint %}
{% endstep %}
{% endstepper %}

### Accessing Your FormSG Instance

#### Web Interface

Open your browser and navigate to:

* **Main Application**: `http://YOUR_VM_IP:5173`
* **Email Testing**: `http://YOUR_VM_IP:1080` (MailDev interface)

#### First Login

1. Go to the admin portal: `http://YOUR_VM_IP:5173/login`
2. Click "Login with Email"
3. Enter your email address
4. Check the MailDev interface (`http://YOUR_VM_IP:1080`) for the OTP code
5. Enter the OTP to complete login

### Scaling

This VM deployment runs all FormSG components on a single server, which limits scaling options. For high-traffic scenarios or high availability requirements, consider moving to a cloud-native deployment with multiple servers.

#### When to Move Beyond VM Deployment

Consider migrating to a more robust deployment when you experience:

* **High traffic**: >1,000 concurrent users or >10,000 daily submissions
* **Availability requirements**: Need 99.9% uptime or zero-downtime deployments
* **Advanced integrations**: Complex workflows requiring multiple services

***

{% hint style="success" %}
**🎉 Congratulations!** You now have FormSG running on a virtual machine. This provides a solid foundation for small-scale production use while maintaining full control over your infrastructure.
{% endhint %}
