Running a document conversion tool in the cloud is fast, but it means handing your raw files to a third-party server.
For organizations handling medical records, financial disclosures, or proprietary internal data, that data transfer is often a non-starter.
Self-hosting changes the equation by keeping the entire processing pipeline inside your own infrastructure.
You maintain total control over data residency, API routing, and retention policies.
Here is exactly how to pull the open-source repository and deploy it on your own hardware.
Why deploy an on-premise form converter instead of using the cloud?
When you use a managed software-as-a-service application, your files travel across the public internet to reach the vendor's load balancers. The vendor processes your document, extracts the text, structures the form, and pushes it to Google.
For many teams, this workflow is perfectly acceptable. But when your baseline requirement involves strict data compliance, sending documents outside your virtual private cloud introduces significant legal and security hurdles. Deploying an open-source converter locally ensures the file never leaves your controlled environment until the final structured data is sent via an encrypted connection to the Google Forms API.
This architectural shift solves several enterprise bottlenecks at once. You bypass external vendor security audits, control your own uptime, and dictate exactly which large language model processes your internal data.
| Compliance need | Self-hosted approach | Cloud-managed approach | Best for |
|---|---|---|---|
| Data residency | Files never leave your local network or private VPC. | Files are processed on the vendor's external servers. | Strict geo-fencing (e.g., GDPR, CCPA). |
| Model selection | Route requests to self-hosted LLMs or specific enterprise API endpoints. | Locked to the vendor's chosen processing models. | Organizations with strict AI vendor approvals. |
| Audit logging | Full access to application logs, network traffic, and container metrics. | Rely on vendor-provided dashboards and export limitations. | Teams needing granular SIEM integration. |
| Network isolation | Can be deployed behind strict firewalls with limited outbound rules. | Requires inbound/outbound access to arbitrary vendor IP ranges. | Zero-trust enterprise environments. |
What are the system and environment prerequisites?
Before cloning the repository, you need to prepare the host machine and configure your external API access. The application is lightweight, but the exact requirements depend on whether you are running bare metal Node.js or using containerization.
Containerization is highly recommended. It prevents dependency conflicts and ensures the application behaves exactly as it does in the development environment.
To run the application reliably, ensure your host system and cloud accounts meet the following baselines.
- Operating system: Any modern Linux distribution (Ubuntu 22.04 LTS recommended), macOS, or Windows via WSL2.
- Hardware resources: A minimum of 1 vCPU and 2GB of RAM. The conversion process is not CPU-intensive, but running the Node runtime inside Docker requires a modest memory baseline.
- Container runtime: Docker Engine v24.0 or higher, and Docker Compose v2.
- Node environment (if running bare metal): Node.js v18 LTS or v20 LTS, plus
npmoryarn. - Google Cloud Platform project: A dedicated GCP project with an active billing account.
- Google APIs enabled: You must explicitly enable both the Google Forms API and the Google Drive API in your GCP console.
- Network egress: Your firewall must permit outbound HTTPS traffic on port 443 to
forms.googleapis.com,drive.googleapis.com, and your chosen LLM provider (e.g.,api.openai.com).
How to deploy Doc2Form from GitHub step-by-step
Pulling the application from GitHub and getting it running requires just a few terminal commands. The repository includes a pre-configured Docker setup that handles building the image and mapping the necessary ports.
If you are deploying to a production server, it is best practice to check out a specific release tag rather than the main branch. This prevents unexpected breaking changes if the upstream repository updates while you are building your image.
Follow these steps to fetch the code, build the container, and start the local server.
- Open your terminal and clone the repository to your local machine or host server.
git clone https://github.com/doc2form/doc2form.git
cd doc2form
- Check out the latest stable release tag to ensure a reliable build.
git checkout tags/v1.2.0 -b deploy-branch
- Copy the example environment template to create your active configuration file.
cp .env.example .env
- Build the Docker image. This step downloads the base Node image, copies the application files, and installs production dependencies inside the container.
docker compose build
- Start the application in detached mode. This runs the container in the background and frees up your terminal.
docker compose up -d
- Verify that the container is running and check the initial startup logs for any immediate errors.
docker compose logs -f
Once the container is running, the application will listen on the port defined in your configuration. By default, you can access the local interface by navigating to http://localhost:3000 in your browser.
However, until you configure your API credentials, the application will not be able to communicate with Google or process any documents.
How to configure your API keys and Google authentication
The most complex part of self-hosting a Google-integrated application is managing the authentication handshake. Google uses Service Accounts to allow server-to-server communication without requiring a human to log in via a browser.
When you create a Service Account in the Google Cloud Console, you generate a private key file. This file contains the cryptographic keys the application uses to prove its identity when calling the Forms API.
You must download this file as a JSON document and place it securely on your server. Do not commit this file to version control.
Here is an example of what the Google Service Account JSON file looks like.
{
"type": "service_account",
"project_id": "doc2form-internal-123",
"private_key_id": "a1b2c3d4e5f6g7h8i9j0",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggS...\n-----END PRIVATE KEY-----\n",
"client_email": "[email protected]",
"client_id": "109876543210987654321",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/form-creator..."
}
Once you have this file saved - for example, at /app/config/service-account.json - you need to update your .env file to point the application to it. You also need to supply your LLM API key and define where the generated forms should be saved.
Below is a standard .env configuration for a self-hosted instance.
PORT=3000
NODE_ENV=production
GOOGLE_APPLICATION_CREDENTIALS=/app/config/service-account.json
GOOGLE_DRIVE_FOLDER_ID=1A2B3C4D5E6F7G8H9I0J
LLM_PROVIDER=openai
LLM_API_KEY=sk-proj-1234567890abcdef1234567890abcdef
Expert tip: A common mistake is authenticating successfully but failing to find the generated form. Service accounts act as invisible users; they create files in their own isolated Google Drive. To see the forms, you must create a folder in your personal or workspace Drive, share that folder with the
client_emailaddress found in your JSON file, and put that folder's ID in your.envfile.
How to troubleshoot common self-hosting deployment errors
Even with a perfect Docker configuration, network policies and cloud permissions can cause issues during your first deployment. Because the application orchestrates file parsing, LLM requests, and Google API calls, a failure in any one of these steps will halt the process.
When an error occurs, always check the container logs first using docker compose logs --tail=50. The logs will specify which part of the pipeline failed.
Here is how to resolve the most frequent deployment and configuration roadblocks.
| Error code or symptom | Root cause | Quick fix |
|---|---|---|
403 PERMISSION_DENIED (Google API) |
The service account does not have edit access to the target Google Drive folder. | Open the target folder in Google Drive, click Share, and grant Editor access to the service account's email address. |
403 Google Forms API has not been used in project... |
The Forms API is disabled in your Google Cloud Platform project. | Visit the GCP console, search for "Google Forms API", and click Enable. Wait 5 minutes for the change to propagate. |
401 Unauthorized (LLM API) |
The LLM API key in your .env file is invalid, expired, or lacks billing credits. |
Verify the key in your provider's dashboard and ensure your account has a positive prepaid balance. |
ECONNREFUSED or Cannot connect to Docker daemon |
The Docker service is not running on your host machine, or your user lacks permissions. | Start the Docker service via systemctl start docker or add your user to the docker group. |
| Form generates but questions are missing | The LLM response timed out or returned improperly formatted JSON. | Increase the timeout limit in your environment variables, or switch to a more capable model (e.g., GPT-4o instead of a smaller local model). |
| Container exits immediately after starting | A syntax error in the .env file or missing required variables. |
Check the logs. Ensure there are no spaces around the = signs in your environment file. |
When does the managed cloud path make more sense?
Self-hosting gives you total control, but it also transfers the burden of maintenance entirely to your team. The open-source path is not a set-it-and-forget-it solution.
Google frequently updates its API payload requirements. LLM providers deprecate older models. When these external dependencies change, a self-hosted instance will break until your engineering team pulls the latest upstream code, rebuilds the containers, and deploys the updates.
If your organization does not strictly require on-premise data isolation, the managed cloud path is usually much more efficient. Relying on a hosted service removes the infrastructure overhead and guarantees that someone else is monitoring API changes.
Consider migrating to a managed solution if you encounter these operational friction points:
- High maintenance overhead: Your team spends more time managing Docker containers, rotating GCP service account keys, and patching Node.js security vulnerabilities than actually using the tool.
- Scaling difficulties: You need to process hundreds of concurrent documents. A single self-hosted container will eventually hit memory limits or rate limits, requiring you to implement queueing systems like Redis and Celery.
- Prompt drift: As LLMs evolve, the system prompts required to extract perfect form structures change. Managed services constantly tune their extraction prompts; self-hosted users must manually test and update them.
- Feature lag: Managed platforms often roll out advanced features - like complex branching logic or specialized converting PDFs to Google Forms pipelines - months before they are stable in the open-source repository.
If your primary goal is simply turning Word documents into Google Forms quickly without involving the IT department, the managed cloud approach will save you days of configuration time.
FAQ
Does the open-source version of Doc2Form support OCR for scanned PDFs?
The base open-source repository relies on standard text extraction libraries. If a PDF contains flat images rather than selectable text, the default parser will return blank results. To process scanned documents locally, you must install and configure Tesseract OCR on your host machine and link it to the application's processing pipeline.
How do I secure my self-hosted instance from unauthorized API abuse?
The Docker container exposes a web interface and API endpoints without built-in user authentication. You must place the application behind a reverse proxy like Nginx or Traefik. From there, you can enforce HTTP Basic Authentication, IP allowlisting, or integrate with an identity provider like Authelia to protect the interface.
Can I run Doc2Form in a completely air-gapped on-premise environment?
No, the system cannot function in a truly air-gapped environment. While you can host the application and a local LLM entirely on your own hardware, the final step requires pushing the structured data to Google's servers. The host machine must have outbound internet access to forms.googleapis.com to successfully create the form.
How do updates work when pulling from the upstream GitHub repository?
Updates require a manual rebuild of your deployment. You must fetch the latest commits from the upstream repository, pull the new code into your local branch, and run docker compose build --no-cache. After the new image compiles, restarting the container will apply the updates.
Self-hosting a document conversion pipeline requires upfront technical investment, but the payoff in data security and architectural control is substantial. When your compliance requirements dictate that files cannot touch a third-party cloud, spinning up Doc2Form on your own infrastructure ensures you get the automation you need without compromising your security posture.