Quick-start template and detailed instructions to run a Forgejo instance on Fly.io.
- Dockerfile 100%
| Caddyfile | ||
| docker-compose.yaml | ||
| Dockerfile | ||
| fly-template.toml | ||
| fly.toml | ||
| LICENSE | ||
| README.md | ||
Forgejo on Fly.io
This process will get you up and running with a fresh Forgejo instance on Fly.io.
Steps:
- Fork this repository, then clone it locally.
- Change the app name at the top of the
fly.tomlfile if you wish to name your Fly app something other than "forgejo" (note: Fly app names must be all lowercase and only letters, numbers, and dashes). - Rename the persistent storage volume (configured at
[[mounts]].source) if preferred, or just use the default name "forgejo_data".- Note: If you decide to alter your Forgejo deployment's default storage location to something other than
/var/lib/gitea, then make sure you update the Fly volume's mount path in yourfly.tomlhere ([[mounts]].destination). Otherwise you will lose all data when your Fly machine rolls.
- Note: If you decide to alter your Forgejo deployment's default storage location to something other than
- The
fly.tomlspecifies a 2vCPU / 512 MB virtual machine (configured in the[[vm]]section). If you're running a very small Forgejo deployment (such as a single-user instance for your own personal projects), you may be able to get away with an even cheaper VM. However, initial installation and setup of Forgejo is a surprisingly resource-intensive process. I recommend starting with the default VM specs until your instance is up and running, then you can experiment with redeploying on a lower-specced machine and see how it works for your needs. Since Fly charges for VMs incrementally, the cost of this should be negligible as long as you remember to redeploy later with the lower specs.- I've tested the full initial Forgejo setup on a 1vCPU / 512 MB machine, and while the process was eventually successful, it rammed into Fly's shared CPU throttling limits immediately. This caused the initial install to take over 30 minutes to complete, and there's very little feedback during that time to show that it hadn't just failed. Try this at your own risk, but I strongly recommend just giving it the extra vCPU to start out.
- Open a terminal and
cdto the top-level directory of your local clone. - Create your Fly App.
- Run
fly launch --no-deploy. - When prompted, select the option to use the existing fly.toml file.
- Select the option to tweak settings — this will open a browser window.
- Choose your Forgejo instance's Fly App name, organization, and region.
- Delete the value for Internal Port entirely.
- This stops
flyctlfrom generating an[http_service]section in yourfly.toml. Ports for this Forgejo deployment are defined in the[[services]]section instead. I'm not sure why Fly doesn't recognize the predefined[[services]]and handle it correctly, but as of June 2026 that's the case.
- This stops
- Choose the size for your Forgejo instance's virtual machine(s). As noted above, a configuration with at least 512mb of memory and 2 vCPUs are recommended to start out with. After initial installation you can likely downgrade to only 1 vCPU for a very small instance.
- Note that even though this page is supposed to pull your configuration from the
fly.tomlfile, as of June 2026 there's a bug where it does not detect your chosen vCPU selection and instead always defaults to "shared-cpu-1x". Don't forget to change that value.
- Note that even though this page is supposed to pull your configuration from the
- Confirm your settings.
- Fly will create your app on the Fly.io side, as well as automatically editing your fly.toml file to include the chosen app name and region.
- IMPORTANT: At the time of this writing, Fly does not fully support the experimental docker-compose configuration. As such, the automatic edit of your fly.toml file will have replaced the
[build.compose]line with a line that just says[build]. Add the.composepart back to that line and save the change. - Double check that Fly didn't add an
[http_service]section. If it did, delete the entire section and re-save the file.
- Run
- For SSH support:
- Fly does not allow utilizing the default SSH port 22 because it's reserved for the
fly ssh consolecommand. Thus, a different port needs to be selected. - As long as we're already using a non-default port (and thus are required to somehow have users do port selection when SSHing — either through our URLs including ports or through their SSH configs), I like to just combine SSH and HTTPS on the same port (443). This allows us to only need to open a single port to the public, and also can get users around some aggressive firewall setups that may fully disallow traffic on ports other than the default HTTP ports.
- To support SSH over port 443, you need to allocate a dedicated IPV4 IP address and free the default shared IP.
- Note: as of June 2026, this costs an extra $2/month on Fly.io. If you don't want to pay the $2, don't want to allow SSH at all, or want to allow it on a different port (in which case you can leverage a shared IP and skip the extra cost), then you'll need to adjust the
FORGEJO__server__*environment variables indocker-compose.yamlto disable or alter Forgejo's SSH configuration as needed. - To continue with the 443 setup described above (which this deployment is preconfigured to assume), run
flyctl ips allocate-v4 && fly ips allocate-v6.- The second command allocates a free IPV6 address, and only needs to be run explicitly because we're starting with the manual IPV4 allocation.
- Note: as of June 2026, this costs an extra $2/month on Fly.io. If you don't want to pay the $2, don't want to allow SSH at all, or want to allow it on a different port (in which case you can leverage a shared IP and skip the extra cost), then you'll need to adjust the
- Fly does not allow utilizing the default SSH port 22 because it's reserved for the
- Set up DNS.
- Run
fly certs add <domain_name>, subbing in the domain name your instance should be running at. - Follow the steps from the flyctl CLI to determine which DNS records you need, then go set them on your DNS provider.
- Fly may warn you that the certs won't provision until your app is running. This is fine — as long as your DNS records are correct then the certs should be issued near-instantly on first startup.
- Run
- This Forgejo deployment can be configured using Docker Compose environment variables. See existing variables for examples. You can find configuration options here: https://forgejo.org/docs/next/admin/config-cheat-sheet/
- Of note is the configuration for
FORGEJO__server__SSH_PORT, which is set to an empty string. As discussed above, this deployment listens for SSH on port 443 — the same port as HTTPS — because the usual SSH port (22) is reserved by Fly for itsfly ssh consolecommand. SettingFORGEJO__server__SSH_PORTto an empty string stops Forgejo from displaying:443after every SSH URL. This makes these URLs much more pleasing to the eye, but technically also makes them invalid without the port being specified elsewhere. Users can include-p 443manually in all of their SSH commands, but obviously the ideal solution is a simple SSH config entry to make this set-it-and-forget-it:
Host example.com User git Port 443 IdentityFile ~/.ssh/id_ed25519 ## <- Replace with your SSH key path- If you don't think that complexity tradeoff is worth it, just set
FORGEJO__server__SSH_PORTto443in yourdocker-compose.yamlto have the port explicitly included on all SSH URLs. That will entirely eliminate this issue at the cost of uglier URLs.
- Of note is the configuration for
- The last step is to update your
Caddyfile:- Change the URL
example.comto the domain name that you're using for your Forgejo installation. - Optionally adjust or entirely remove the rate limit configurations. (FYI if you're uncertain here: the default limits are values I actively use for Forgejo, and they've been working well for me.)
- If you didn't go with port 443 for SSH, you can remove the entire L4 add-on from both the Caddyfile and the Dockerfile. If you went with a different port for SSH then you'll need to add config for that, but you shouldn't need the L4 add-on to do so.
- Change the URL
- Everything is ready, it's time to fire up Forgejo!
- Deploy your app with
fly deploy.- You can also use
fly deploy --local-onlyto build Caddy locally rather than waiting on the Depot builder (your local machine and Internet connection likely determine which of these is faster).
- You can also use
- You can follow along with the deploy in another terminal tab by running
fly logs. - If everything works, you should be able to visit your Forgejo instance in a web browser at your chosen domain name (or the default Fly-provided domain name). You'll be greeted with the Forgejo initial configuration screen.
- Most of the config defaults should be good, with a few exceptions:
- You'll likely want to set the instance title and slogan.
- Make sure the SSH server port is set to 443, or whatever you chose for it.
- I'm using Argon2 for password hashing on my instance and haven't had a problem with memory usage, but YMMV.
- If you aren't opening your instance to public sign-ups yet, make sure that setting is disabled. This will require creating an admin user within the initial config screen.
- When you're ready, hit the button to complete setup of your instance. Assuming you granted enough CPU and memory to your VM, this shouldn't take long.
- The screen should auto-reload when it's ready, but you can try checking a pulse with the
fly logscommand in your terminal if things are really dragging on.
- Most of the config defaults should be good, with a few exceptions:
- Deploy your app with
- Congratulations, your Forgejo instance is up and running!
- I recommend setting up an SSH key and attempting to clone a repository with it sooner rather than later to make sure your SSH configuration landed smoothly.
Other references: