[{"data":1,"prerenderedAt":204},["ShallowReactive",2],{"seo-verification":3,"blog-host-forgejo-on-your-own-vps-ma-en":6,"promo-bar-likely":203},{"google":4,"bing":5},"EycwPY2XMyTkVzas3n1ygeNJFGAH513qrMjfDljzsMQ","",{"key":7,"data":8},"blog-host-forgejo-on-your-own-vps-ma-en",{"id":9,"slug":10,"slugs":11,"title":15,"excerpt":16,"readTime":17,"views":18,"isPinned":19,"noindex":19,"publishedAt":20,"updatedAt":21,"category":22,"categories":28,"featuredImage":30,"bgImage":31,"posterImage":32,"relatedSolution":30,"intro":33,"sections":34,"ctaTitle":143,"ctaBody":144,"ctaButton":145,"ctaUrl":146,"relatedPosts":147},75,"host-forgejo-on-your-own-vps",{"fr":12,"en":10,"ar":13,"es":14},"heberger-forgejo","استضافة-forgejo-على-خادم-vps-الخاص-بك","alojar-forgejo-en-un-vps","Self-Host Forgejo on Your VPS: Complete 2025 Guide","Deploy Forgejo on your VPS with Docker, SSL, Actions runners and hardened security. Step-by-step guide for a sovereign Git forge.",10,9,false,"2026-04-06T00:00:00+00:00","2026-11-08T01:13:14+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},7,"Self-hosting","self-hosting","bg-indigo-500\u002F10 text-indigo-400","cloud",[29],{"id":23,"name":24,"slug":25,"color":26,"icon":27},null,"\u002Fblog\u002Fcovers\u002Fbg.svg","\u002Fblog\u002Fcovers\u002Fheberger-forgejo-poster.svg","Forgejo is the lightweight, community-driven Git forge that emerged as an alternative to Gitea. Compatible with GitHub Actions, easy to migrate to, and respectful of your data, it can be running on a VPS in under an hour. This guide covers everything: server sizing, Docker deployment, SSL configuration, CI\u002FCD runners, post-install hardening and zero-downtime updates.",[35,39,51,54,76,79,82,85,89,92,95],{"type":36,"title":37,"body":38},"h2","Why Choose Forgejo for Your Self-Hosted Git Forge","Forgejo was born in 2022 as a community fork of Gitea, driven by concerns about the project's governance. Its development is entirely community-led, licensed under GPLv3+ since v9.0 (August 2024; MIT before that), with no dependency on a commercial entity. For teams wanting full control over their source code, CI\u002FCD pipelines, and artifacts without relying on GitHub, GitLab, or Bitbucket, Forgejo is one of the lightest options available. The interface will feel familiar to any GitHub user, migration from Gitea is seamless, and GitHub Actions compatibility lowers the barrier to adoption.",{"type":40,"title":41,"items":42},"ul","Concrete Benefits of a Self-Hosted Forgejo",[43,44,45,46,47,48,49,50],"Full sovereignty: your code never leaves your infrastructure","GitHub Actions compatible via Forgejo Actions — reuse existing workflows","Low memory footprint: a small VPS is enough for a small team","Built-in package registry: npm, PyPI, Maven, Helm, OCI container","No limits on private repositories or collaborators","ActivityPub federation in progress — future interoperability with other forges","Open-source, auditable, no pricing surprises","Controlled updates: you decide when to upgrade",{"type":36,"title":52,"body":53},"Hardware and Software Requirements with Real Numbers","Size your VPS according to your actual team size before deploying Forgejo. For 1–5 developers with a few dozen repositories, 1 vCPU and 1 GB RAM are sufficient. For 5–20 developers with active CI\u002FCD, plan for 2 vCPU and 2 GB RAM. Beyond 20 developers or for large repositories (monorepos, binaries), 4 vCPU and 4 GB RAM ensure a smooth experience. For storage, account for your Git repository volume plus 20% headroom for artifacts and backups.\n\nOn the network side, three ports must be open in your firewall: port 80 (HTTP, for Let's Encrypt validation), port 443 (HTTPS, web traffic), and port 2222 (Git SSH, to avoid conflicting with the admin SSH on port 22). On the software side, you need Docker Engine ≥ 24, Docker Compose v2, and a domain name pointing to your VPS.",{"type":55,"title":56,"steps":57},"steps","Deploy Forgejo with Docker and SSL",[58,61,64,67,70,73],{"title":59,"body":60},"Prepare the environment","Create the directories that will persist data outside the container:\n\n```bash\nmkdir -p \u002Fopt\u002Fforgejo\u002F{data,config,db}\nchown -R 1000:1000 \u002Fopt\u002Fforgejo\n```\n\nCreate `\u002Fopt\u002Fforgejo\u002F.env` with your values:\n\n```env\nFORGEJO_DOMAIN=git.yourdomain.com\nFORGEJO_SSH_PORT=2222\n```\n\nAdd a generated database password, never a sample one, then protect the file:\n\n```bash\necho \"POSTGRES_PASSWORD=$(openssl rand -hex 32)\" >> \u002Fopt\u002Fforgejo\u002F.env\nchmod 600 \u002Fopt\u002Fforgejo\u002F.env\n```",{"title":62,"body":63},"Create the docker-compose.yml","```yaml\nservices:\n  forgejo:\n    image: codeberg.org\u002Fforgejo\u002Fforgejo:17\n    restart: unless-stopped\n    environment:\n      - USER_UID=1000\n      - USER_GID=1000\n      - FORGEJO__database__DB_TYPE=postgres\n      - FORGEJO__database__HOST=db:5432\n      - FORGEJO__database__NAME=forgejo\n      - FORGEJO__database__USER=forgejo\n      - FORGEJO__database__PASSWD=${POSTGRES_PASSWORD}\n    volumes:\n      - \u002Fopt\u002Fforgejo\u002Fdata:\u002Fdata\n    ports:\n      - \"127.0.0.1:3000:3000\"\n      - \"${FORGEJO_SSH_PORT:-2222}:22\"\n    depends_on:\n      - db\n\n  db:\n    image: postgres:16-alpine\n    restart: unless-stopped\n    environment:\n      - POSTGRES_DB=forgejo\n      - POSTGRES_USER=forgejo\n      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}\n    volumes:\n      - \u002Fopt\u002Fforgejo\u002Fdb:\u002Fvar\u002Flib\u002Fpostgresql\u002Fdata\n```",{"title":65,"body":66},"Start the services","```bash\ncd \u002Fopt\u002Fforgejo\ndocker compose up -d\ndocker compose logs -f forgejo\n```\n\nWait until the logs show the web server listening on port 3000. Forgejo runs its schema migrations automatically on first start.",{"title":68,"body":69},"Configure the reverse proxy and SSL with Caddy","Caddy is the simplest option for automatic Let's Encrypt certificates. Install it and create `\u002Fetc\u002Fcaddy\u002FCaddyfile`:\n\n```\ngit.yourdomain.com {\n  reverse_proxy localhost:3000\n}\n```\n\nStart Caddy: `systemctl enable --now caddy`. The TLS certificate is issued and renewed automatically. If you prefer nginx, configure a standard `proxy_pass http:\u002F\u002F127.0.0.1:3000;` block with Certbot.",{"title":71,"body":72},"Complete the instance setup","Open `https:\u002F\u002Fgit.yourdomain.com` in your browser. The setup wizard appears once only. Fill in the domain, the SSH URL (`ssh:\u002F\u002Fgit.yourdomain.com:2222`), the admin email address, and disable public registration on this screen if your forge is for private use. Once the wizard is submitted, the configuration is locked in `\u002Fopt\u002Fforgejo\u002Fdata\u002Fgitea\u002Fconf\u002Fapp.ini`.",{"title":74,"body":75},"Install a Forgejo Actions runner","The runner executes your workflows' code: install it on a dedicated machine if you can. In *Site Administration → Actions → Runners* (`\u002Fadmin\u002Factions\u002Frunners`), click *Create new runner*: Forgejo displays a UUID and a token. Generate the configuration file (`docker run --rm data.forgejo.org\u002Fforgejo\u002Frunner:13 forgejo-runner generate-config > data\u002Frunner-config.yml`), copy the instance URL, the UUID and the token into the `server.connections` section, and declare your labels (for example `ubuntu-latest:docker:\u002F\u002Fnode:20`) in the `runner` section. Then deploy the runner with its own Docker daemon (docker-in-docker) instead of mounting the host's `\u002Fvar\u002Frun\u002Fdocker.sock`, which would give every job root access to the server:\n\n```yaml\nservices:\n  docker-in-docker:\n    image: docker:dind\n    privileged: true\n    command: [\"dockerd\", \"-H\", \"tcp:\u002F\u002F0.0.0.0:2375\", \"--tls=false\"]\n    restart: unless-stopped\n\n  runner:\n    image: data.forgejo.org\u002Fforgejo\u002Frunner:13\n    depends_on:\n      - docker-in-docker\n    environment:\n      DOCKER_HOST: tcp:\u002F\u002Fdocker-in-docker:2375\n    user: \"1001:1001\"\n    volumes:\n      - .\u002Fdata:\u002Fdata\n    command: forgejo-runner daemon --config runner-config.yml\n    restart: unless-stopped\n```\n\nThe docker-in-docker daemon's port 2375 stays on Compose's internal network: never publish it. The runner appears in the interface as soon as it connects. Each label sets the execution mode: **docker:\u002F\u002F** (container, recommended), **lxc:\u002F\u002F** (LXC container) or **host** (directly on the machine, with no isolation at all: keep it for trusted tasks).",{"type":36,"title":77,"body":78},"Writing Your First Forgejo Actions Workflows","Compatibility with GitHub Actions syntax is broad. Create `.forgejo\u002Fworkflows\u002Fci.yml` at the root of your repository:\n\n```yaml\non:\n  push:\n    branches: [main]\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@v4\n      - name: Run tests\n        run: |\n          npm ci\n          npm test\n```\n\nThe `runs-on` labels correspond to the labels declared when registering the runner. You can define multiple runners with different labels (e.g., `arm64`, `gpu`, `high-memory`) and target the right environment per job. Artifacts and caching work with the same official actions as on GitHub.",{"type":36,"title":80,"body":81},"Post-Install Security: Essential Settings","A freshly installed Forgejo is functional but not hardened. Here are the six points to address before opening the forge to your team.\n\n**Disable public registration.** If you did not do it in the wizard, add `FORGEJO__service__DISABLE_REGISTRATION=true` to the container's environment variables (or `DISABLE_REGISTRATION = true` in the `[service]` section of `app.ini`): only an administrator can then create accounts. On an internal forge, nobody should be able to create an account without an invitation.\n\n**Enable 2FA for administrators.** Every admin account must enable two-factor authentication under *Settings → Security*. To enforce it, set `GLOBAL_TWO_FACTOR_REQUIREMENT` in the `[security]` section of `app.ini` (`admin` for administrators, `all` for every user). The `REQUIRE_SIGNIN_VIEW` setting only forces users to sign in to view the forge.\n\n**SSH keys only.** Disable password authentication in the host server's `\u002Fetc\u002Fssh\u002Fsshd_config` (`PasswordAuthentication no`). For Git SSH (port 2222), Forgejo only accepts public keys registered in user profiles — this is its default behavior.\n\n**Webhook secrets.** When creating each webhook (to external CI, Slack, etc.), always fill in the *Secret* field. Forgejo signs the payload with HMAC-SHA256; your receiver must verify this signature before processing the event.\n\n**Private packages.** If you use the built-in package registry, remember that a package inherits its owner's visibility: publish it under a private organization or account to restrict it to members. Access tokens for publishing should have minimal scope (`write:package` only, never a global admin token).\n\n**Firewall.** Close all ports except 80, 443, and 2222. Port 3000 (internal Forgejo) must never be exposed directly; it is consumed only by the reverse proxy on loopback, which is why the compose file publishes it on `127.0.0.1:3000`. A port published by Docker bypasses ufw rules: only this 127.0.0.1 binding keeps it off the Internet.",{"type":36,"title":83,"body":84},"Updating Forgejo Without Downtime","The Docker update procedure is straightforward and requires only a few seconds of unavailability.\n\n```bash\ncd \u002Fopt\u002Fforgejo\n# 1. Pull the new image\ndocker compose pull forgejo\n\n# 2. Back up the database before any migration\ndocker compose exec db pg_dump -U forgejo forgejo > backup-$(date +%Y%m%d).sql\n\n# 3. Restart the service\ndocker compose up -d forgejo\n\n# 4. Verify schema migrations\ndocker compose logs forgejo | grep -i migrat\n```\n\nForgejo runs its migrations automatically on startup. Check that the logs report no migration error. In case of a migration error, restore the SQL backup and report the issue on the Forgejo tracker. The `17` tag only follows 17.x releases: to move to the next major version, change the tag in the compose file after a full backup, and always read the release notes before jumping major versions. Forgejo refuses to start on a database newer than itself: rolling back means restoring the backup.",{"type":86,"title":87,"body":88},"tip","Migrate from Gitea in Five Minutes","Forgejo is a direct fork of Gitea: upgrading from Gitea is supported up to and including version 1.22, going through Forgejo v10.0.x first. To migrate, stop Gitea, copy its data directory (`\u002Fdata` or `\u002Fopt\u002Fgitea`) to `\u002Fopt\u002Fforgejo\u002Fdata`, replace the image with `codeberg.org\u002Fforgejo\u002Fforgejo:10` in your docker-compose, restart, then upgrade to the current version. Forgejo automatically detects the Gitea schema and applies its own migrations. Your repositories, users, SSH keys, webhooks, and issues are fully preserved. Gitea versions after 1.22 are not covered by Forgejo's official upgrade guide: do not attempt a direct switch.",{"type":36,"title":90,"body":91},"Troubleshooting: Most Common Errors","**SSH connection refused on port 2222.** First verify the port is published by Docker (`docker compose ps` → Ports column). Then test from the client: `ssh -p 2222 git@git.yourdomain.com`. If the response is `PTY allocation request failed`, the connection is working — Forgejo responds `Hi \u003Cuser>! You've successfully authenticated`. If you get `Connection refused`, the firewall is blocking the port: `ufw allow 2222\u002Ftcp`.\n\n**Runner showing offline in the interface.** The runner contacts Forgejo over outbound HTTPS. Verify the runner container can resolve and reach `git.yourdomain.com`. A self-signed certificate requires mounting your CA in the container. Restart the runner after fixing connectivity: `docker compose restart runner`.\n\n**Push rejected by a pre-receive hook.** Forgejo may reject a push if a branch protection rule is active (code review required, mandatory CI tests) or if a file size rule is exceeded. The git error message contains the details. For large binaries (> 100 MB), use Git LFS: Forgejo supports the LFS protocol natively.\n\n**Slow interface after several months.** Run the Git garbage collector on active repositories from the admin panel: *Site Administration → Dashboard → Maintenance operations*, repository garbage collection task. To automate this, enable the `[cron.git_gc_repos]` scheduled task in `app.ini` (`ENABLED = true`; it runs every 72 h by default).",{"type":86,"title":93,"body":94},"ActivityPub Federation: What Forgejo Is Building","Forgejo is building forge federation with ForgeFed, an extension of the ActivityPub protocol (the same one used by Mastodon). It remains experimental and disabled by default (`[federation] ENABLED = false`): moderation and access control are not developed yet, and the project warns that an incompatible change can \"burn\" the instance's domain for any future federation. Do not enable it on a production forge. Full federation — cross-instance forking, inter-forge pull requests — is being standardized within the ForgeFed working group. If your collaborators are on different forges, this evolution will eventually allow contributing without creating an account on each instance.",{"type":96,"title":97,"headers":98,"rows":103},"comparison","Forgejo vs Gitea vs GitLab CE: Choosing Your Forge",[99,100,101,102],"Criterion","Forgejo","Gitea","GitLab CE",[104,109,113,118,122,126,129,133,138],[105,106,107,108],"Governance","Community (Codeberg e.V.)","Commercial (CommitGo)","Commercial (GitLab Inc)",[110,111,111,112],"Minimum RAM","Low (small VPS)","8 GB (16 GB recommended)",[114,115,116,117],"GitHub Actions compatibility","Yes (Forgejo Actions)","Yes (Gitea Actions)","No (GitLab CI, own syntax)",[119,120,121,121],"Package registry","Yes (multi-format)","Yes",[123,124,125,125],"ActivityPub federation","In progress (ForgeFed)","No",[127,128,121,121],"Migration from GitHub","Yes (mirror + import)",[130,131,131,132],"Admin interface","Simple, built-in","Full-featured but heavy",[134,135,136,137],"License","GPLv3+ (since v9.0)","MIT","MIT (CE) \u002F EE (paid)",[139,140,141,142],"Release frequency","Quarterly (+ LTS)","Several per year","Monthly","A VPS ready for Forgejo in minutes","Our VPS Cloud range gives you a clean Debian or Ubuntu server, SSD storage and a dedicated IP. One `docker compose up` later, your forge is live.","See our VPS Cloud plans","\u002Fvps-cloud",[148,164,185],{"id":149,"slug":150,"slugs":151,"title":155,"excerpt":156,"readTime":18,"views":157,"isPinned":19,"noindex":19,"publishedAt":158,"updatedAt":159,"category":160,"categories":161,"featuredImage":30,"bgImage":31,"posterImage":163,"relatedSolution":30},261,"when-saas-vendors-bundle-ai-migrating-to-self-hosting",{"fr":152,"en":150,"ar":153,"es":154},"migrer-saas-self-hosting-bundling-ia","ارتفاع-تكاليف-saas-46-متى-تستضيف-بنفسك","migrar-de-saas-al-self-hosting-por-la-ia","When SaaS vendors bundle AI: migrating to self-hosting","PricePulse H1 2026: +46% SaaS costs for 50-person teams. Mattermost, Nextcloud, Plane and Forgejo self-host on a VPS. Migration guide.",0,"2026-08-14T00:00:00+00:00","2026-10-20T23:18:07+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},[162],{"id":23,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Fmigrer-saas-self-hosting-bundling-ia-poster.svg",{"id":165,"slug":166,"slugs":167,"title":171,"excerpt":172,"readTime":173,"views":174,"isPinned":19,"noindex":19,"publishedAt":175,"updatedAt":176,"category":177,"categories":182,"featuredImage":30,"bgImage":31,"posterImage":184,"relatedSolution":30},229,"docker-compose-in-production-10-point-checklist",{"fr":168,"en":166,"ar":169,"es":170},"docker-compose-production-checklist","docker-compose-في-الإنتاج-قائمة-التحقق-من-10-نقاط","checklist-docker-compose-en-produccion","Docker Compose in Production: 10-Point Checklist","Docker Compose in production: 10 settings, health checks, secrets, rollback, troubleshooting and moving from docker-compose v1 to docker compose on Ubuntu 26.04.",12,1,"2026-08-06T00:00:00+00:00","2026-10-23T13:27:09+00:00",{"id":178,"name":179,"slug":180,"color":181,"icon":180},3,"Deployment","deploiement","bg-success\u002F10 text-success",[183],{"id":178,"name":179,"slug":180,"color":181,"icon":180},"\u002Fblog\u002Fcovers\u002Fdocker-compose-production-checklist-poster.svg",{"id":186,"slug":187,"slugs":188,"title":192,"excerpt":193,"readTime":194,"views":174,"isPinned":19,"noindex":19,"publishedAt":175,"updatedAt":159,"category":195,"categories":200,"featuredImage":30,"bgImage":31,"posterImage":202,"relatedSolution":30},228,"initial-linux-server-hardening",{"fr":189,"en":187,"ar":190,"es":191},"durcissement-serveur-linux-initial","تصليب-الخادم-linux-الأولي","hardening-inicial-servidor-linux","Initial Linux Server Hardening","Create a sudo user, configure SSH with keys, enable UFW and fail2ban on Ubuntu or Debian in under an hour.",8,{"id":194,"name":196,"slug":197,"color":198,"icon":199},"Security & Monitoring","securite-monitoring","bg-rose-500\u002F10 text-rose-400","security",[201],{"id":194,"name":196,"slug":197,"color":198,"icon":199},"\u002Fblog\u002Fcovers\u002Fdurcissement-serveur-linux-initial-poster.svg",true,1794270408876]