---
title: "Deploy GitLab CE | (Just Updated) Your Repos Survive Redeploys, 4GB RAM Required"
description: "Needs 4GB RAM. Repos, database and uploads survive every redeploy."
category: "Other"
url: https://railway.com/deploy/gitlab-ce-or-just-updated-your-repos-sur
---

# Deploy GitLab CE | (Just Updated) Your Repos Survive Redeploys, 4GB RAM Required

Needs 4GB RAM. Repos, database and uploads survive every redeploy.

**[Deploy GitLab CE | (Just Updated) Your Repos Survive Redeploys, 4GB RAM Required on Railway](https://railway.com/template/gitlab-ce-or-just-updated-your-repos-sur)**

Machine-readable deploy manifest (JSON, validated by TemplateCI): https://railway.com/deploy/gitlab-ce-or-just-updated-your-repos-sur/manifest.json

- **Creator:** SuperSlowSloth
- **Category:** Other
- **Total deploys:** 1

## Template content

### gitlab

- **Image:** gitlab/gitlab-ce@sha256:c7c87778c3380e4f93843f7329e3f2dc4aed1b90f29d05e56d8834ce50dccc54
- **Public domain:** Yes

## Documentation

# Deploy and Host GitLab CE on Railway

GitLab Community Edition is a complete self-hosted DevOps platform — Git repository
hosting, merge requests, issue tracking, a container registry, CI/CD pipelines, a wiki
and a full REST and GraphQL API. This template runs it on the configuration it actually
needs on Railway, rather than the one that merely boots.

**This template requires 4 GB of RAM and therefore the Hobby plan.** That is stated
first because it is the single fact that decides whether your deploy works. Measured on
the official `gitlab/gitlab-ce` image: at a 2 GB cap the omnibus first-boot reconfigure
is OOM-killed after about 220 seconds having reached 1.94 GiB, so **every Free (0.5 GB)
and Trial (1 GB) deploy of any GitLab listing fails 100% of the time** and no
configuration rescues it. At 4 GB it boots cleanly and settles around 2.3–3.0 GiB.

## About Hosting GitLab CE

GitLab CE is not a single process. The omnibus image runs Puma, Sidekiq, Gitaly, Redis,
PostgreSQL, gitlab-workhorse, gitlab-kas and nginx under a `runit` supervisor inside one
container, and configures all of them from a Chef converge on every boot. Three things
follow from that, and this template addresses each one.

**Your repositories, database and uploads all live under `/var/opt/gitlab`.** Git repos
are at `/var/opt/gitlab/git-data/repositories`, the PostgreSQL cluster at
`/var/opt/gitlab/postgresql`, attachments and avatars at
`/var/opt/gitlab/gitlab-rails/uploads`. Without a persistent volume on that exact path,
all of it is container-local — so **every redeploy destroys every repository**, silently
and with no error, and the instance comes back looking like a fresh install. This
template mounts a Railway volume at `/var/opt/gitlab`. Verified by creating a project,
destroying the container entirely, bringing it back on the same volume, and reading the
project and its on-disk `.git` directory back.

**Puma's default listener is `127.0.0.1:8080` — which is exactly the port Railway
injects.** Point nginx at Railway's port without moving Puma and the two collide: Puma
dies on `Address already in use - bind(2) for "127.0.0.1" port 8080 (Errno::EADDRINUSE)`
and is restarted forever by runit, while nginx stays up and answers every request with
`502`. The container reports itself running the whole time. This template puts nginx on
Railway's port and moves Puma to 8092.

**`/etc/gitlab` is not persisted, and does not need to be.** The file that matters there
is `gitlab-secrets.json`, which holds the key bases used to encrypt columns in the
database; lose it and your existing 2FA secrets, CI/CD variables and access tokens
become undecryptable even though the database survived. Rather than juggling a second
mount, this template seeds `db_key_base`, `secret_key_base` and `otp_key_base` from
Railway variables, which are stable across redeploys — so the secrets are regenerated
identically every boot. Verified: a personal access token created before a full
container replacement still authenticated afterwards.

Two more fixes worth naming. `external_url` is wired to your Railway domain as
**`https://`** with `nginx['listen_https'] = false`, so TLS terminates at Railway's edge
while clone URLs, invite links, webhook targets and OAuth callbacks are all generated
with the correct public scheme and host. And the `root` password is seeded from a
Railway-generated variable instead of being left to omnibus's
`/etc/gitlab/initial_root_password`, a file that is **deleted 24 hours after first boot**
and lives on ephemeral disk anyway — the usual way a deployer ends up locked out of
their own GitLab.

The image is pinned by digest.

## Why Deploy GitLab CE on Railway?

Railway gives GitLab a persistent volume, a TLS domain wired into `external_url` from
the first boot, and enough RAM on Hobby to run the whole omnibus stack in one service
with no external database to provision. You get your own GitLab — repositories, issues,
merge requests, CI — on your own infrastructure, with the root account already sealed
behind a generated password before the URL answers.

**There is no healthcheck on this template, deliberately.** A cold first boot runs the
full omnibus reconfigure and the database migrations before nginx serves anything, which
takes several minutes; Railway's default healthcheck window would kill the container
part-way through. The boot is idempotent, so a restart resumes rather than corrupting.
Expect the URL to answer `502` for the first few minutes after deploy, then `200`.

## Common Use Cases

- Self-hosted Git for a team that wants its source code and issue history on its own infrastructure
- A private GitLab for CI/CD, container registry and merge-request review without a seat-priced SaaS bill
- A migration target off GitHub or Bitbucket, using GitLab's built-in importers

## Dependencies for GitLab CE

- None external. PostgreSQL, Redis and Gitaly all run inside the omnibus image.

### Deployment Dependencies

- [GitLab CE documentation](https://docs.gitlab.com/ee/)
- [Omnibus configuration reference](https://docs.gitlab.com/omnibus/settings/configuration.html)
- [Official Docker image](https://hub.docker.com/r/gitlab/gitlab-ce)

### Post-deploy

1. Wait for the public URL to return the sign-in page — first boot takes several minutes.
2. Sign in as `root` with the value of the `GITLAB_ROOT_PASSWORD` variable.
3. Change that password, and consider disabling open sign-up under **Admin → Settings → General → Sign-up restrictions**.
4. SSH cloning is not exposed by this template; use the HTTPS clone URLs, which are already correct.


## Similar templates

- [Rocky Linux](https://railway.com/deploy/rocky-linux) — Hosted Rocky Linux 9 workspace with SSH and persistent storage. 🚀
- [Foundry Virtual Tabletop](https://railway.com/deploy/X5tR6G) — A Self-Hosted & Modern Roleplaying Platform
- [Letta Code Remote](https://railway.com/deploy/letta-code-remote) — Run a Letta Code agent 24/7. No inbound ports, just deploy.

Open this page in a browser: https://railway.com/deploy/gitlab-ce-or-just-updated-your-repos-sur
