[{"data":1,"prerenderedAt":224},["ShallowReactive",2],{"seo-verification":3,"blog-migrate-gitlab-com-to-self-managed-gitlab-vps-en":6},{"google":4,"bing":5},"EycwPY2XMyTkVzas3n1ygeNJFGAH513qrMjfDljzsMQ","",{"key":7,"data":8},"blog-migrate-gitlab-com-to-self-managed-gitlab-vps-en",{"id":9,"slug":10,"slugs":11,"title":15,"excerpt":16,"readTime":17,"views":18,"isPinned":19,"publishedAt":20,"updatedAt":21,"category":22,"categories":27,"featuredImage":29,"bgImage":30,"posterImage":31,"relatedSolution":29,"intro":32,"sections":33,"ctaTitle":160,"ctaBody":161,"ctaButton":162,"ctaUrl":163,"relatedPosts":164},498,"migrate-gitlab-com-to-self-managed-gitlab-vps",{"fr":12,"en":10,"ar":13,"es":14},"migrer-gitlab-com-vers-self-managed-vps","ترحيل-gitlab-com-إلى-gitlab-ذاتي-الاستضافة-على-vps","migrar-gitlab-com-a-gitlab-autoalojado-vps","Migrate GitLab.com to a Self-Managed Instance on a VPS","Move groups and projects from GitLab.com to your own GitLab instance on a VPS: export, direct transfer, members, CI\u002FCD variables and registry images to rebuild by hand.",11,0,false,"2026-10-23T00:00:00+00:00","2026-10-23T23:43:01+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":25},3,"Deployment","deploiement","bg-success\u002F10 text-success",[28],{"id":23,"name":24,"slug":25,"color":26,"icon":25},null,"\u002Fblog\u002Fcovers\u002Fbg.svg","\u002Fblog\u002Fcovers\u002Fmigrer-gitlab-com-vers-self-managed-vps-poster.svg","Your agency keeps several clients' code on one GitLab.com account, and retention and billing are not set by you. Taking control back means running GitLab on your own VPS, but a project export does not carry everything: CI\u002FCD variables, registry images, webhooks and tokens stay behind. This guide plans the migration, walks through direct transfer, settles how members are matched and rebuilds what is missing, with a switchover order you can reverse. The old project stays read-only until you validate.",[34,38,47,50,80,83,117,120,123,138,142,145,154,157],{"type":35,"title":36,"body":37},"h2","Why leave GitLab.com for a self-managed instance","When the pricing of a SaaS tool shifts, like the recent Atlassian Cloud increase covered in \u003Ca href=\"\u002Fblog\u002Fatlassian-double-choc-tarif-octobre-decembre-2026\">our article on the double price shock\u003C\u002Fa>, teams re-examine their whole development toolchain. For an agency the question is concrete: the code of ten clients lives on a single account, at a third party, with retention and access rules you do not set yourself.\n\nA self-managed instance moves those decisions to you: where repositories are stored, how long artifacts are kept, who can sign in, and what it costs each month. The price of that freedom is a migration job that GitLab does not fully do for you.\n\nThis guide does not repeat the choice of forge, covered in \u003Ca href=\"\u002Fblog\u002Fcomparatif-forge-git-self-hosted-2026\">the forge comparison\u003C\u002Fa>, nor the installation, described in \u003Ca href=\"\u002Fblog\u002Finstaller-gitlab-ce-vps\">the GitLab CE installation guide\u003C\u002Fa>. It starts from a GitLab instance that is already online and only covers the move from GitLab.com to it.",{"type":39,"title":40,"items":41},"ul","What you gain by taking hosting back",[42,43,44,45,46],"**Access under your control** — accounts, groups and roles live on your instance, not on a SaaS account shared between clients.","**Retention you decide** — how long artifacts and logs are kept and how large the registry grows are all set in the administration area.","**A bill that follows your VPS** — the cost depends on the machine you size, not on a seat count.","**A domain name of your own** — the repository answers on `git.your-domain.com`, with your certificate and your firewall.","**A step-by-step migration** — the old project stays in place, read-only, until the new one is validated.",{"type":35,"title":48,"body":49},"What the migration does not carry, to inventory first","The official documentation for project export lists what is not exported: child pipeline history, pipeline triggers, CI\u002FCD job traces and artifacts, container and package registry images, CI\u002FCD variables, webhooks, encrypted tokens, the number of required approvals, deploy keys allowed to push to protected branches, secure files and pipeline schedule variables. Deploy keys are not imported either: you must enable them again in the imported project.\n\nDirect transfer has its own exclusion list, which overlaps with the first: CI\u002FCD variables, webhooks, container registry images, the package registry, job logs and job artifacts. At group level, CI\u002FCD variables, deploy tokens and push rules do not follow either.\n\nWrite this inventory in a table before you start: one row per project, one column per missing item, one column for the person who rebuilds it. This document, more than the export itself, protects you the day the old access closes.",{"type":51,"title":52,"headers":53,"rows":57},"comparison","Project export or direct transfer: what each method covers",[54,55,56],"Item","Project export (file)","Direct transfer",[58,62,66,68,70,72,76],[59,60,61],"Granularity","One project at a time, through a downloaded file","Whole groups, with or without their projects, from the interface",[63,64,65],"CI\u002FCD variables","Not exported","Not migrated",[67,64,65],"Container registry images",[69,64,65],"Webhooks",[71,64,65],"Job logs and artifacts",[73,74,75],"Members","Matched if the source public email equals the destination primary email","Matched if the source public email equals a confirmed destination email",[77,78,79],"What the instance needs","An administrator performs the import","Feature enabled by an administrator, token with the `api` scope on the source",{"type":35,"title":81,"body":82},"Prerequisites: versions, permissions and instance resources","First rule, the version. A file import accepts exports from a version up to two minor versions behind the destination, and the documentation asks that the destination be at least at the source version. For direct transfer, the documentation recommends GitLab 16.8 or later on both sides, and asks that a source be no more than two minor versions behind the destination. GitLab.com moves continuously: aim for the latest stable release on your instance, update it before migrating, not after, and reread the accepted gap in the documentation on the day.\n\nOn permissions, you need the Owner role on the source group, an administrator on the target instance, and a personal access token with the `api` scope created on GitLab.com. The two instances must reach each other over HTTPS, with free space in `\u002Ftmp`.\n\nOn resources, our editorial recommendation: 4 vCPU and 8 GB of RAM for an instance that also hosts the registry, an NVMe disk sized to the combined size of repositories and images, and runners on a separate VPS as soon as builds get heavy. The installation itself is described in \u003Ca href=\"\u002Fblog\u002Finstaller-gitlab-ce-vps\">the GitLab CE on VPS guide\u003C\u002Fa>.",{"type":84,"title":85,"steps":86},"steps","Plan and run the migration, from inventory to switchover",[87,90,93,96,99,102,105,108,111,114],{"title":88,"body":89},"Inventory groups, projects and dependencies","List every group, every project, its variables, webhooks, runners and integrations. Note who owns each one on the client side.",{"title":91,"body":92},"Update the target instance","Check the version in the administration area and aim for the latest stable release, at least equal to GitLab.com, before any import.",{"title":94,"body":95},"Create users on the target","Members are not created during migration. Create accounts beforehand, with the primary email each person uses on GitLab.com.",{"title":97,"body":98},"Plan one group per client","Create on the target one group or subgroup per client, with minimal permissions, before importing.",{"title":100,"body":101},"Have public emails published on the source","Each member sets a public email in their GitLab.com profile, at least until the import is done.",{"title":103,"body":104},"Enable direct transfer on the target instance","An administrator enables group migration by direct transfer in the application settings. It is off by default on a self-managed instance.",{"title":106,"body":107},"Start the group import","On the target, choose **Create new** then **New group** then **Import group**, enter `https:\u002F\u002Fgitlab.com` and your token, then **Connect instance**. Select the groups with **Import with projects**.",{"title":109,"body":110},"Export standalone projects by hand","For a project outside a group, open **Settings** then **General** then **Advanced** then **Export project**, download the file and import it on the target.",{"title":112,"body":113},"Follow the import and read the errors","The **Status** column shows progress. On a failed or partial import, **Show errors** details the cause. Allow several hours for a large number of projects.",{"title":115,"body":116},"Hook up the registry and CI","Rebuild variables and images as described below, then run a full pipeline on the target before touching the old project.",{"type":35,"title":118,"body":119},"Members and assignees: the matching rule","On a self-managed instance, the published rule is this: users must already exist on the destination, and the public email of the source account must match the primary email of the destination account. If the conditions are met, the person is added as a direct member. Otherwise, the association changes to the user performing the import: your comment authors and assignees all end up under your name.\n\nBefore importing, check the **Public email** field on every GitLab.com profile. For a project export, you can also add public emails by editing the `project_members.ndjson` file in the archive. The owner of the top-level group must run the export so that direct and inherited members are included, and an administrator must perform the import.\n\nWith direct transfer, imported memberships are first associated with placeholder users, pending reassignment. An **Import user memberships** checkbox also lets you skip importing memberships. In that case, the source public email against a confirmed destination email decides the match, not the primary email as with a file import.\n\nFor an agency, structure the target before importing: one top-level group per client, or one subgroup per client under an agency group. Give each client the minimal role on its own group only (Reporter or Developer rather than Owner), keep the Owner role for the internal team, and you can later move a client out by transferring its group or exporting its projects, without touching the others.",{"type":35,"title":121,"body":122},"CI\u002FCD variables and container registry: rebuild by hand","Variables do not travel, because GitLab treats them as sensitive. List them on the source with the API: `curl --header \"PRIVATE-TOKEN: \u003Ctoken>\" \"https:\u002F\u002Fgitlab.com\u002Fapi\u002Fv4\u002Fprojects\u002F\u003Cid>\u002Fvariables\"`. The list gives the key, the `masked` and `protected` attributes and, usually, the value; but not every value is necessarily readable, depending on the version and how the variable was created.\n\nThen recreate them on the target with `curl --request POST --header \"PRIVATE-TOKEN: \u003Ctoken>\" --form \"key=NAME\" --form \"value=value\" \"https:\u002F\u002Fgit.your-domain.com\u002Fapi\u002Fv4\u002Fprojects\u002F\u003Cid>\u002Fvariables\"`. The key accepts 255 characters among `A-Z`, `a-z`, `0-9` and `_`. When the value is missing or stays hidden, recreate the secret at its provider and store it in the agency vault.\n\nGroup variables are recreated from the group's CI\u002FCD settings. Runners are registered again on the new instance: their tokens do not follow.",{"type":84,"title":124,"steps":125},"Move registry images to the new URL",[126,129,132,135],{"title":127,"body":128},"Enable the registry on the target instance","In `\u002Fetc\u002Fgitlab\u002Fgitlab.rb`, set `registry_external_url` over HTTPS, for example `https:\u002F\u002Fregistry.your-domain.com`, then run `sudo gitlab-ctl reconfigure`. The registry requires a TLS certificate.",{"title":130,"body":131},"Create a token for each side","A token with `read_registry` is enough to pull images, and `write_registry` as well to push them.",{"title":133,"body":134},"Pull each image from the old URL","Sign in with `docker login registry.gitlab.com`, then `docker pull registry.gitlab.com\u002Fgroup\u002Fproject\u002Fimage:tag`.",{"title":136,"body":137},"Retag, then push to the target","Run `docker tag registry.gitlab.com\u002Fgroup\u002Fproject\u002Fimage:tag registry.your-domain.com\u002Fgroup\u002Fproject\u002Fimage:tag`, then `docker login registry.your-domain.com` and `docker push registry.your-domain.com\u002Fgroup\u002Fproject\u002Fimage:tag`. Registry repository paths are written in lowercase.",{"type":139,"title":140,"body":141},"tip","Keep the way back open","Delete nothing on the source. Archive the old project or remove write access, keep it readable, then run a pipeline and a full `git clone` from the target. As long as the client has not signed off on validation, the switchover stays reversible: you only need to reopen the old project.",{"type":35,"title":143,"body":144},"Troubleshooting: authentication and import errors","On `docker login` or `docker push`, the message `access forbidden` means, according to the documentation, that the `Authorization` header was stripped before reaching GitLab, often by a proxy in front of the instance. Check the reverse proxy configuration.\n\nAn `UNAUTHORIZED` (401) error points to wrong or expired credentials, missing scopes, or a password used with two-factor authentication enabled: use a token instead. A `DENIED` (403) means the credentials are valid but have no right on the registry.\n\nOn a large image, `unauthorized: authentication required` signals a token that expired before the push finished. An administrator can lengthen its lifetime.\n\nOn the import side, a milestone title that already exists gets a unique suffix such as `18.0 (imported-…)`: rename the milestone before migrating to avoid it.",{"type":39,"title":146,"items":147},"Checks before you cut off the old access",[148,149,150,151,152,153],"**Identical repositories** — compare branches and tags, then do a full clone from the target.","**Full green pipeline** — a pipeline on the main branch with variables recreated and runners registered again.","**Images present** — every tag used by a deployment exists in the new registry.","**Members and roles reviewed** — no author or assignee has moved to the account that started the import.","**Webhooks and deploy keys recreated** — chat, deployment and monitoring integrations included.","**Written sign-off from the client** — the old project only closes after that agreement.",{"type":35,"title":155,"body":156},"The official documentation","The rules in this guide come from the GitLab documentation: \u003Ca href=\"https:\u002F\u002Fdocs.gitlab.com\u002Fee\u002Fuser\u002Fproject\u002Fsettings\u002Fimport_export.html\">project export and import\u003C\u002Fa>, \u003Ca href=\"https:\u002F\u002Fdocs.gitlab.com\u002Fee\u002Fuser\u002Fgroup\u002Fimport\u002Fdirect_transfer_migrations.html\">group migration by direct transfer\u003C\u002Fa>, \u003Ca href=\"https:\u002F\u002Fdocs.gitlab.com\u002Fee\u002Fuser\u002Fgroup\u002Fimport\u002Fmigrated_items.html\">migrated items\u003C\u002Fa>, \u003Ca href=\"https:\u002F\u002Fdocs.gitlab.com\u002Fee\u002Fapi\u002Fproject_level_variables.html\">project variables API\u003C\u002Fa>, \u003Ca href=\"https:\u002F\u002Fdocs.gitlab.com\u002Fee\u002Fuser\u002Fpackages\u002Fcontainer_registry\u002Fauthenticate_with_container_registry.html\">registry authentication\u003C\u002Fa> and \u003Ca href=\"https:\u002F\u002Fdocs.gitlab.com\u002Fee\u002Fadministration\u002Fpackages\u002Fcontainer_registry.html\">registry on a self-managed instance\u003C\u002Fa>. Reread them on the date of your migration: the lists of migrated items evolve.",{"type":35,"title":158,"body":159},"Next: consolidate around your instance","Once the projects are validated, the instance becomes the central point of the agency's portfolio. For a heavier registry, \u003Ca href=\"\u002Fblog\u002Fself-host-harbor-registry-vps\">Harbor on a VPS\u003C\u002Fa> can take over. If your migration comes from another ticketing tool, \u003Ca href=\"\u002Fblog\u002Fmigrer-jira-openproject-plane-vps-2026\">the Jira to OpenProject or Plane guide\u003C\u002Fa> follows the same inventory logic. And if you are still unsure about the forge, \u003Ca href=\"\u002Fblog\u002Fmigrer-gitlab-vers-gitea-vps-2026\">moving from GitLab to Gitea\u003C\u002Fa> remains a lighter option.","Take back control of your clients' code","An agency that hosts its repositories on its own instance controls access, retention and billing. On ServOrbit the instance runs on a root VPS with a dedicated IPv4 address, and the repository's domain name is managed in the same place as your hosting and your reseller account.","Explore agency solutions","\u002Fsolutions\u002Fagences",[165,181,205],{"id":166,"slug":167,"slugs":168,"title":172,"excerpt":173,"readTime":174,"views":23,"isPinned":19,"publishedAt":175,"updatedAt":176,"category":177,"categories":178,"featuredImage":29,"bgImage":30,"posterImage":180,"relatedSolution":29},235,"install-gitlab-ce-on-a-vps-complete-guide",{"fr":169,"en":167,"ar":170,"es":171},"installer-gitlab-ce-vps","تثبيت-gitlab-ce-على-vps-دليل-شامل","instalar-gitlab-ce-en-un-vps-guia-completa","Install GitLab CE on a VPS: complete guide","Deploy GitLab CE on your VPS with Docker Compose. Covers CVE-2026-90970 (CVSS 9.9): AI Gateway RCE, vulnerable versions and update commands.",18,"2026-08-07T00:00:00+00:00","2026-10-20T23:18:07+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":25},[179],{"id":23,"name":24,"slug":25,"color":26,"icon":25},"\u002Fblog\u002Fcovers\u002Finstaller-gitlab-ce-vps-poster.svg",{"id":182,"slug":183,"slugs":184,"title":188,"excerpt":189,"readTime":190,"views":18,"isPinned":19,"publishedAt":191,"updatedAt":192,"category":193,"categories":199,"featuredImage":29,"bgImage":30,"posterImage":201,"relatedSolution":202},352,"migrate-gitlab-to-gitea-vps-2026",{"fr":185,"en":183,"ar":186,"es":187},"migrer-gitlab-vers-gitea-vps-2026","الانتقال-من-gitlab-إلى-gitea-على-vps-في-2026","migrar-gitlab-a-gitea-en-un-vps-en-2026","Migrate from GitLab to Gitea on a VPS in 2026","GitLab.com made namespaces with more than 5 members read-only from August 15, 2026. Here is how to migrate to self-hosted Gitea without losing history.",10,"2026-09-16T00:00:00+00:00","2026-10-20T23:18:06+00:00",{"id":194,"name":195,"slug":196,"color":197,"icon":198},4,"Development","developpement","bg-warning\u002F10 text-warning","dev",[200],{"id":194,"name":195,"slug":196,"color":197,"icon":198},"\u002Fblog\u002Fcovers\u002Fmigrer-gitlab-vers-gitea-vps-2026-poster.svg",{"categorySlug":203,"appSlug":204},"development","gitea",{"id":206,"slug":207,"slugs":208,"title":212,"excerpt":213,"readTime":190,"views":18,"isPinned":19,"publishedAt":214,"updatedAt":215,"category":216,"categories":221,"featuredImage":29,"bgImage":30,"posterImage":223,"relatedSolution":29},398,"atlassian-pricing-shock-oct-2026-hike-and-usage-billing",{"fr":209,"en":207,"ar":210,"es":211},"atlassian-double-choc-tarif-octobre-decembre-2026","atlassian-رفع-الاسعار-اكتوبر-2026-فوترة-الاستخدام","atlassian-subida-oct-2026-facturacion-por-uso","Atlassian pricing shock: Oct. 2026 hike and usage billing","Atlassian raises Cloud prices 7–10% on October 13, 2026, then bills automation steps and Rovo AI credits on December 3. Simulate the impact and assess VPS self-hosting.","2026-09-30T00:00:00+00:00","2026-10-20T23:18:05+00:00",{"id":217,"name":218,"slug":219,"color":220,"icon":219},5,"Comparison","comparatif","bg-info\u002F10 text-info",[222],{"id":217,"name":218,"slug":219,"color":220,"icon":219},"\u002Fblog\u002Fcovers\u002Fatlassian-double-choc-tarif-octobre-decembre-2026-poster.svg",1792799399578]