{"id":31887,"date":"2026-07-03T08:14:00","date_gmt":"2026-07-03T06:14:00","guid":{"rendered":"https:\/\/contabo.com\/blog\/?p=31887"},"modified":"2026-07-02T10:34:00","modified_gmt":"2026-07-02T08:34:00","slug":"secure-gitea-server-hardening","status":"publish","type":"post","link":"https:\/\/contabo.com\/blog\/secure-gitea-server-hardening\/","title":{"rendered":"Securing a Self-Hosted Gitea Server: A Hardening Checklist"},"content":{"rendered":"\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1200\" height=\"630\" src=\"https:\/\/contabo.com\/blog\/wp-content\/uploads\/2026\/07\/blog-head_guide-securing-a-self-hosted-gitea-server_EN.webp\" alt=\"Securing a Self-Hosted Gitea Server: A Hardening Checklist (head image)\" class=\"wp-image-31951\" srcset=\"https:\/\/contabo.com\/blog\/wp-content\/uploads\/2026\/07\/blog-head_guide-securing-a-self-hosted-gitea-server_EN.webp 1200w, https:\/\/contabo.com\/blog\/wp-content\/uploads\/2026\/07\/blog-head_guide-securing-a-self-hosted-gitea-server_EN-600x315.webp 600w, https:\/\/contabo.com\/blog\/wp-content\/uploads\/2026\/07\/blog-head_guide-securing-a-self-hosted-gitea-server_EN-768x403.webp 768w\" sizes=\"auto, (max-width: 1200px) 100vw, 1200px\" \/><\/figure>\n\n\n\n<p><strong>In short.<\/strong> A default Gitea install leaves the web installer open, registration unrestricted, and repositories public by default. This checklist covers the five `app.ini` settings that close those gaps (`INSTALL_LOCK`, `DISABLE_REGISTRATION`, `REQUIRE_SIGNIN_VIEW`, `RUN_USER`, secret keys), plus 2FA enforcement (Gitea 1.24+), access token scoping, private-by-default repository visibility, branch protection, and a hardened Nginx reverse-proxy configuration with the headers Gitea requires. OS and SSH hardening are covered in the linked guides below.<\/p>\n\n\n\n<div class=\"wp-block-uagb-advanced-heading uagb-block-fbc69ed2\"><h2 class=\"uagb-heading-text\">Before You Start: The VPS Security Baseline<\/h2><\/div>\n\n\n\n<p>Gitea hardening builds on top of a secured host. Before working through the steps below, make sure your VPS already has:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>SSH key authentication with password login disabled.<\/strong> See the <a href=\"https:\/\/contabo.com\/blog\/how-to-set-up-ssh\/\">SSH key authentication guide<\/a> for setup instructions.<\/li>\n\n\n\n<li><strong>The Contabo Firewall activated<\/strong>. Every Contabo VPS and VDS includes a <a href=\"https:\/\/contabo.com\/en\/firewall\/\">free network-level firewall <\/a>managed from the Customer Control Panel &#8211; no installation required. See <a href=\"https:\/\/help.contabo.com\/en\/support\/solutions\/articles\/103000390430-firewall-what-is-it-and-how-does-it-protect-my-vps-vds-?_gl=1%2Av09t6o%2A_gcl_aw%2AR0NMLjE3ODI3MjI0NzYuQ2owS0NRandyNGpTQmhDU0FSSXNBT1gxRS1JNVRKc0lZNlJCMV9MNHNORWZVd3E5WFlxekdZU2pzdDBmRG9Eb0hhdy1aY2otZmlxc2FMa2FBc09WRUFMd193Y0I.%2A_gcl_au%2AMTI5NjcwNTExNS4xNzgwOTIwMjM1LjE2NDYzMDU5MjcuMTc4MjM4MDgxNS4xNzgyMzgwODUw%2A_ga%2AMTMxMTI4NDExMS4xNzQ4NDExMzI4%2A_ga_YFPNZBGTF3%2AczE3ODI3MjI1NDQkbzQ4JGcwJHQxNzgyNzIyNjUyJGo1NSRsMCRoODY3OTkyMTY5\">our self-help article<\/a> for a step-by-step walkthrough.<\/li>\n\n\n\n<li><strong>Fail2Ban installed and configured<\/strong>. See the <a href=\"https:\/\/contabo.com\/blog\/what-is-fail2ban-and-how-to-use-it-on-a-vps\/\">Fail2Ban guide<\/a> to block repeated login attempts at the network level.<\/li>\n\n\n\n<li><strong>A non-root sudo user running the service<\/strong>. See the <a href=\"https:\/\/contabo.com\/blog\/a-practical-guide-to-superuser-accounts-sudo-root\/\">sudo user guide<\/a> for the correct way to provision a `git` system account.<\/li>\n\n\n\n<li><strong>Regular host patching<\/strong>. See the <a href=\"https:\/\/contabo.com\/blog\/the-importance-of-patching-and-patching-best-practices-linux-windows\/\">VPS patching guide<\/a> for an automated approach to keeping your OS packages current.<\/li>\n<\/ul>\n\n\n\n<p>Each item is a one-sentence entry point; the linked tutorials cover the full procedure. Do not skip this baseline: Gitea-specific hardening does nothing for an attacker who already has SSH access through a weak host configuration.<\/p>\n\n\n\n<div class=\"wp-block-uagb-advanced-heading uagb-block-8727a040\"><h2 class=\"uagb-heading-text\">Gitea-Specific Hardening (the Part Nothing Else Covers)<\/h2><\/div>\n\n\n\n<p>These items are unique to Gitea. They do not appear in any OS guide, and a default Gitea install does not apply most of them. Work through each section; all changes go into `app.ini`, which lives at `\/etc\/gitea\/app.ini` on most Linux package installs or at `custom\/conf\/app.ini` in a binary install.<\/p>\n\n\n\n<div class=\"wp-block-uagb-advanced-heading uagb-block-698bccf3\"><h3 class=\"uagb-heading-text\">Lock Down the app.ini Configuration<\/h3><\/div>\n\n\n\n<p>Five settings in `app.ini` are unique to Gitea and not covered by any OS hardening guide. Set all of them before exposing your instance to the network:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code><strong>`INSTALL_LOCK = true`<\/strong><\/code><\/strong> closes the <code>\/install<\/code> web endpoint. The web installer sets this automatically on completion, but verify it is present in <code>app.ini<\/code> before going live \u2014 if it is missing or <code>false<\/code> for any reason, anyone who reaches the endpoint can reconfigure your instance from scratch.<\/li>\n\n\n\n<li><strong>`REQUIRE_SIGNIN_VIEW = true`<\/strong> forces login before browsing any repository, issue, or user profile. Essential for private team instances.<\/li>\n\n\n\n<li><strong>`RUN_USER = git`<\/strong> tells Gitea to run as a dedicated non-root system account, not as root. Check your systemd unit and fix this first if it is wrong.<\/li>\n\n\n\n<li><strong>`SECRET_KEY` and `INTERNAL_TOKEN`<\/strong> are both auto-generated by the installer. Verify each is a long random string, not a blank or placeholder. Rotate them if you are unsure of their origin.<\/li>\n<\/ul>\n\n\n\n<p>After any change to `app.ini`, restart and verify:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo systemctl restart gitea &amp;&amp; sudo systemctl status gitea<\/code><\/pre>\n\n\n\n<div class=\"wp-block-uagb-advanced-heading uagb-block-b3e00439\"><h3 class=\"uagb-heading-text\">Disable Open Registration and Control Sign-Up<\/h3><\/div>\n\n\n\n<p>Set `DISABLE_REGISTRATION = true` in the `[service]` section of `app.ini`. This stops anyone from creating their own account; new users must be provisioned by an administrator via <strong>Site Administration &gt; Users<\/strong> or the `gitea admin user create` CLI command. If you need external sign-in via OAuth or LDAP, you can still configure those sources for pre-existing accounts: create the user in Gitea first and then link the OAuth identity through their profile.<\/p>\n\n\n\n<div class=\"wp-block-uagb-advanced-heading uagb-block-4b3abcef\"><h3 class=\"uagb-heading-text\">Enforce 2FA and Strong Auth<\/h3><\/div>\n\n\n\n<p>Gitea supports TOTP-based 2FA natively. Users enroll via <strong>Settings &gt; Security &gt; Two-Factor Authentication<\/strong> using any RFC 6238-compatible app (Google Authenticator, Authy, 1Password, and similar).<\/p>\n\n\n\n<p>To enforce 2FA across all users, add the following to the `[service]` section of `app.ini` (requires Gitea 1.24 or later):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;service]\nTWO_FACTOR_AUTH = enforced<\/code><\/pre>\n\n\n\n<p>After restarting, any user who has not enrolled in 2FA will be redirected to the enrollment page on their next login and locked out of repositories until they complete it. Gitea Enterprise has its own flag for this (`ENFORCE_TWO_FACTOR_AUTH` in `[security]`), but on community Gitea 1.24+, `TWO_FACTOR_AUTH = enforced` should cover the same ground.<\/p>\n\n\n\n<div class=\"wp-block-uagb-advanced-heading uagb-block-f92634dd\"><h3 class=\"uagb-heading-text\">Access Tokens and Deploy Keys Hygiene<\/h3><\/div>\n\n\n\n<p>Scope every personal access token to the minimum permissions it needs. Gitea supports fine-grained token scopes (for example, `read:repository` or `write:package`) under <strong>Settings &gt; Applications<\/strong>. Set an expiry date on every token; ones that never expire accumulate silently. For read-only CI\/CD access, create a dedicated token scoped to `read:repository` only rather than using a full-access personal token. Rotate any token on suspected exposure immediately.&nbsp;<\/p>\n\n\n\n<div class=\"wp-block-uagb-advanced-heading uagb-block-65a71f7f\"><h3 class=\"uagb-heading-text\">Repository and Org Access Control<\/h3><\/div>\n\n\n\n<p>To make all new repositories private by default, set the following in the `[repository]` section of `app.ini`:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;repository]\nDEFAULT_PRIVATE = true<\/code><\/pre>\n\n\n\n<p>This means the &#8220;Private&#8221; checkbox is pre-ticked whenever a user creates a new repository. If you want to go further and prevent repositories from ever being made public, set `FORCE_PRIVATE = true` instead &#8211; administrators can still change visibility, but regular users cannot. For access control, use organisations and teams rather than direct per-user permissions, and assign the minimum role needed: Reader, Writer, or Owner. Enable branch protection on repositories that receive production deployments: go to <strong>Repository Settings &gt; Branches<\/strong>, add a rule for your default branch, require at least one review approval, and disable force-push.&nbsp;<\/p>\n\n\n\n<div class=\"wp-block-uagb-advanced-heading uagb-block-f1e0a1d5\"><h2 class=\"uagb-heading-text\">Reverse-Proxy and TLS Hardening for Gitea<\/h2><\/div>\n\n\n\n<p>Gitea can handle TLS directly, but the recommended approach is to put a reverse proxy in front and terminate TLS there. This section covers Nginx. Gitea does not need to know about TLS in this setup; it just needs to know its public URL.<\/p>\n\n\n\n<p><strong>app.ini &#8211; required settings for any reverse-proxy setup<\/strong><\/p>\n\n\n\n<p>Set these in the `[server]` and `[session]` sections before bringing the proxy up:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;server]\nROOT_URL = https:\/\/git.example.com\/\n\n&#91;session]\nCOOKIE_SECURE = true<\/code><\/pre>\n\n\n\n<p>`ROOT_URL` must match the public HTTPS URL exactly. A mismatch breaks clone URLs, OAuth redirects, and webhook payloads. `COOKIE_SECURE = true` marks session cookies as Secure so browsers only send them over HTTPS; without it, cookies issued through an HTTPS proxy can be replayed over HTTP.<\/p>\n\n\n\n<p><strong>Nginx server block<\/strong><\/p>\n\n\n\n<p>The proxy headers below are required by Gitea, not optional. Without `X-Forwarded-Proto` and `X-Real-IP`, Gitea cannot see the real client IP or determine the request scheme, which breaks IP-based rate limiting, audit logs, and OAuth flows.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>server {\n&nbsp;&nbsp;&nbsp;&nbsp;listen 443 ssl;\n&nbsp;&nbsp;&nbsp;&nbsp;server_name git.example.com;\n\n&nbsp;&nbsp;&nbsp;&nbsp;ssl_certificate &nbsp; &nbsp; \/etc\/letsencrypt\/live\/git.example.com\/fullchain.pem;\n&nbsp;&nbsp;&nbsp;&nbsp;ssl_certificate_key \/etc\/letsencrypt\/live\/git.example.com\/privkey.pem;\n\n&nbsp;&nbsp;&nbsp;&nbsp;# Security headers\n&nbsp;&nbsp;&nbsp;&nbsp;add_header Strict-Transport-Security \"max-age=63072000; includeSubDomains; preload\";\n&nbsp;&nbsp;&nbsp;&nbsp;add_header X-Frame-Options SAMEORIGIN;\n &nbsp;&nbsp;&nbsp;add_header X-Content-Type-Options nosniff;\n&nbsp;&nbsp;&nbsp;&nbsp;add_header Referrer-Policy strict-origin-when-cross-origin;\n\n&nbsp;&nbsp;&nbsp;&nbsp;# Hide Gitea version\n&nbsp;&nbsp;&nbsp;&nbsp;proxy_hide_header X-Gitea-Version;\n\n &nbsp;&nbsp;&nbsp;# Rate-limit the login and sign-up routes\n &nbsp;&nbsp;&nbsp;limit_req zone=gitea_auth burst=5 nodelay;\n\n&nbsp;&nbsp;&nbsp;&nbsp;location \/ {\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;client_max_body_size 512M;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy_pass http:\/\/127.0.0.1:3000;\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# Required headers \u2014 do not remove\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy_set_header Host&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $host;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy_set_header X-Real-IP &nbsp; &nbsp; &nbsp; &nbsp; $remote_addr;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy_set_header X-Forwarded-For &nbsp; $proxy_add_x_forwarded_for;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy_set_header X-Forwarded-Proto $scheme;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy_set_header Connection&nbsp; &nbsp; &nbsp; &nbsp; $http_connection;\n &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy_set_header Upgrade &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $http_upgrade;\n&nbsp;&nbsp;&nbsp;&nbsp;}\n}\nserver {\n&nbsp;&nbsp;&nbsp;&nbsp;listen 80;\n&nbsp;&nbsp;&nbsp;&nbsp;server_name git.example.com;\n&nbsp;&nbsp;&nbsp;&nbsp;return 301 https:\/\/$host$request_uri;\n}<\/code><\/pre>\n\n\n\n<p>Define the rate-limit zone in the `http` block of `nginx.conf` (outside the `server` block):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>limit_req_zone $binary_remote_addr zone=gitea_auth:10m rate=10r\/m;<\/code><\/pre>\n\n\n\n<p>`client_max_body_size 512M` matches the value in the Gitea docs. Without it, repository pushes and file uploads over the default Nginx limit (1 MB) return a 413 error.<\/p>\n\n\n\n<p>Issue TLS certificates via Let&#8217;s Encrypt with Certbot; see the <a href=\"https:\/\/help.contabo.com\/en\/support\/solutions\/articles\/103000312197-how-do-i-install-an-ssl-certificate-on-my-linux-server-using-let-s-encrypt-\">How Do I Install an SSL Certificate on My Linux Server Using Let&#8217;s Encrypt?<\/a> for the full procedure.<\/p>\n\n\n\n<p>After any Nginx change, reload rather than restart to avoid dropping active connections:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo nginx -t &amp;&amp; sudo systemctl reload nginx<\/code><\/pre>\n\n\n\n<div class=\"wp-block-uagb-advanced-heading uagb-block-4ed95b81\"><h2 class=\"uagb-heading-text\">Backups and Update Discipline<\/h2><\/div>\n\n\n\n<div class=\"wp-block-uagb-advanced-heading uagb-block-2a127f79\"><h3 class=\"uagb-heading-text\">Backing Up Gitea<\/h3><\/div>\n\n\n\n<p>Gitea ships a `dump` subcommand that archives repositories, the database, configuration, and attachments into a single zip file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo systemctl stop gitea\nsudo -u git gitea dump -c \/etc\/gitea\/app.ini --file \/backups\/gitea-$(date +%Y%m%d).zip\nsudo systemctl start gitea<\/code><\/pre>\n\n\n\n<p>The dump includes the SQLite database or a plain SQL export. For PostgreSQL or MySQL, take a separate database dump before running `gitea dump`:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># PostgreSQL\npg_dump -U gitea gitea &gt; \/backups\/gitea-db-$(date +%Y%m%d).sql\n\n# MySQL \/ MariaDB\nmysqldump -u gitea -p gitea &gt; \/backups\/gitea-db-$(date +%Y%m%d).sql<\/code><\/pre>\n\n\n\n<p>Store backups off-server. Contabo offers two complementary options:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Auto Backup Add-On<\/strong> &#8211; a paid <a href=\"https:\/\/contabo.com\/en\/auto-backup\/\">Add-On for Cloud VPS<\/a> that creates daily automated backups of your entire VPS disk, stored off-server on a separate Contabo storage system for up to 10 days. This gives you a full system restore point, useful for rolling back a failed Gitea upgrade or recovering from a compromised host.<\/li>\n\n\n\n<li><strong>Manual offload via rclone<\/strong> &#8211; the `gitea dump` archive is a portable, Gitea-specific export you control. Sync it to Contabo Object Storage with rclone for long-term retention beyond 10 days. See the <a href=\"https:\/\/contabo.com\/blog\/linux-server-backup-using-rclone\/\">rclone backup guide<\/a> for the full procedure.<\/li>\n<\/ul>\n\n\n\n<p>For a production Gitea instance, both are worth running: Auto Backup for fast full-system recovery, `gitea dump` plus Object Storage for long-term archival and portability.<\/p>\n\n\n\n<div class=\"wp-block-uagb-advanced-heading uagb-block-7e55a41f\"><h3 class=\"uagb-heading-text\">Staying Current<\/h3><\/div>\n\n\n\n<p>Gitea releases patch versions frequently, and security fixes travel in patch releases. Subscribe to the Gitea release feed at `https:\/\/github.com\/go-gitea\/gitea\/releases.atom` so you get notified. Before any update, take a full `gitea dump` and a database snapshot; Gitea&#8217;s database migrations run automatically on startup and are not reversible without a backup. If you run a team deployment, test updates on a staging instance first. Running a single patch version behind is acceptable; running multiple minor versions behind is not.<\/p>\n\n\n\n<div class=\"wp-block-uagb-advanced-heading uagb-block-61d28c92\"><h2 class=\"uagb-heading-text\">Detecting a Compromise<\/h2><\/div>\n\n\n\n<p>Gitea generates access logs, push logs, and admin audit logs. These are the first place to look if you suspect unauthorized access. See the <a href=\"https:\/\/contabo.com\/blog\/indicators-that-your-instance-has-been-compromised\/\">indicators your instance has been compromised guide<\/a> for a full list of signals to monitor and the response steps to take. As a baseline, watch for unexpected new user accounts, SSH keys added to existing accounts, and repositories that were private and are now public.<\/p>\n\n\n\n<div class=\"wp-block-uagb-advanced-heading uagb-block-56c787ab\"><h2 class=\"uagb-heading-text\">Why Run a Hardened Gitea on Contabo<\/h2><\/div>\n\n\n\n<p>Hosting Gitea on a Contabo VPS gives you ample resources. Your CI runners, your Git processes, and your database all get the CPU and RAM you paid for, without contention from other tenants.<\/p>\n\n\n\n<p>For teams subject to GDPR or internal data-sovereignty policies, EU data residency matters. Choosing an <a href=\"https:\/\/contabo.com\/en\/locations\/europe\/\">EU data center <\/a>keeps source code and commit history in EU jurisdiction, on infrastructure that is 100% GDPR-compliant.<\/p>\n\n\n\n<p>Snapshots are worth highlighting in the context of Gitea updates. Before running a major upgrade, <a href=\"https:\/\/help.contabo.com\/en\/support\/solutions\/articles\/103000270385-how-do-i-create-a-snapshot-of-my-server-\">take a snapshot of the entire VPS<\/a> through the Customer Control Panel. If the migration fails or introduces a regression, you roll back in minutes rather than restoring from a database backup.<\/p>\n\n\n\n<p>Entry level VPS plans start at less than 7 bucks per month and give you enough headroom to run Gitea alongside a PostgreSQL database and an Nginx proxy without resource pressure.<\/p>\n\n\n\n<div class=\"wp-block-uagb-advanced-heading uagb-block-da6c56dc\"><h2 class=\"uagb-heading-text\">FAQ: Gitea Security<\/h2><\/div>\n\n\n\n<div class=\"schema-faq wp-block-yoast-faq-block\"><div class=\"schema-faq-section\" id=\"faq-question-1782724184592\"><strong class=\"schema-faq-question\">How do I disable public sign-up in Gitea?<\/strong> <p class=\"schema-faq-answer\">Add `DISABLE_REGISTRATION = true` under `[service]` in `app.ini` and restart Gitea. New accounts must then be created by an administrator via <strong>Site Administration > Users <\/strong>or `gitea admin user create`. Note that this also blocks OAuth-based account creation &#8211; create users manually first and link OAuth identities through their profile.<\/p> <\/div> <div class=\"schema-faq-section\" id=\"faq-question-1782724213173\"><strong class=\"schema-faq-question\">Does Gitea support two-factor authentication?<\/strong> <p class=\"schema-faq-answer\">Yes. Users enroll via <strong>Settings > Security > Two-Factor Authentication<\/strong> using any TOTP app. To enforce it site-wide, add `TWO_FACTOR_AUTH = enforced` under `[service]` in `app.ini` and restart (requires Gitea 1.24+). Gitea Enterprise has a separate flag for this. API access via personal tokens is not gated by 2FA regardless of edition.<\/p> <\/div> <div class=\"schema-faq-section\" id=\"faq-question-1782724236268\"><strong class=\"schema-faq-question\">How do I put Gitea behind HTTPS?<\/strong> <p class=\"schema-faq-answer\">Set <code>ROOT_URL = https:\/\/git.example.com\/<\/code> in <code>[server]<\/code> and <code>COOKIE_SECURE = true<\/code> in <code>[session]<\/code> in <code>app.ini<\/code>. Point Nginx at <code>http:\/\/127.0.0.1:3000<\/code> and pass the required headers (<code>Host<\/code>, <code>X-Real-IP<\/code>, <code>X-Forwarded-For<\/code>, <code>X-Forwarded-Proto<\/code>). Issue a certificate via Certbot &#8211; see <a href=\"https:\/\/help.contabo.com\/en\/support\/solutions\/articles\/103000312197-how-do-i-install-an-ssl-certificate-on-my-linux-server-using-let-s-encrypt-\">How Do I Install an SSL Certificate on My Linux Server Using Let&#8217;s Encrypt?<\/a> for the full procedure.<\/p> <\/div> <div class=\"schema-faq-section\" id=\"faq-question-1782821607286\"><strong class=\"schema-faq-question\">How do I back up a Gitea server?<\/strong> <p class=\"schema-faq-answer\">Run <code>gitea dump -c \/etc\/gitea\/app.ini<\/code> to produce a zip archive of repositories, configuration, database, and attachments. For PostgreSQL or MySQL, take a separate <code>pg_dump<\/code> or <code>mysqldump<\/code> first. Store archives off-server &#8211; <a href=\"https:\/\/contabo.com\/en\/auto-backup\/\">Contabo Auto Backup<\/a> covers full-disk daily snapshots, or sync the dump to Object Storage with rclone for long-term retention.<\/p> <\/div> <\/div>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Running Gitea on your own VPS gives you full control over your code, but a default install leaves several attack surfaces open. This checklist covers every Gitea-specific hardening step, from locking down app.ini to securing your reverse proxy.<\/p>\n","protected":false},"author":65,"featured_media":31951,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"_uag_custom_page_level_css":"","site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"set","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":"","_members_access_role":[],"_members_access_error":""},"categories":[18],"tags":[],"ppma_author":[1489],"class_list":["post-31887","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tutorials"],"uagb_featured_image_src":{"full":["https:\/\/contabo.com\/blog\/wp-content\/uploads\/2026\/07\/blog-head_guide-securing-a-self-hosted-gitea-server_EN.webp",1200,630,false],"thumbnail":["https:\/\/contabo.com\/blog\/wp-content\/uploads\/2026\/07\/blog-head_guide-securing-a-self-hosted-gitea-server_EN-150x150.webp",150,150,true],"medium":["https:\/\/contabo.com\/blog\/wp-content\/uploads\/2026\/07\/blog-head_guide-securing-a-self-hosted-gitea-server_EN-600x315.webp",600,315,true],"medium_large":["https:\/\/contabo.com\/blog\/wp-content\/uploads\/2026\/07\/blog-head_guide-securing-a-self-hosted-gitea-server_EN-768x403.webp",768,403,true],"large":["https:\/\/contabo.com\/blog\/wp-content\/uploads\/2026\/07\/blog-head_guide-securing-a-self-hosted-gitea-server_EN.webp",1200,630,false],"1536x1536":["https:\/\/contabo.com\/blog\/wp-content\/uploads\/2026\/07\/blog-head_guide-securing-a-self-hosted-gitea-server_EN.webp",1200,630,false],"2048x2048":["https:\/\/contabo.com\/blog\/wp-content\/uploads\/2026\/07\/blog-head_guide-securing-a-self-hosted-gitea-server_EN.webp",1200,630,false]},"uagb_author_info":{"display_name":"Julia Mink","author_link":"https:\/\/contabo.com\/blog\/author\/julia-mink\/"},"uagb_comment_info":0,"uagb_excerpt":"Running Gitea on your own VPS gives you full control over your code, but a default install leaves several attack surfaces open. This checklist covers every Gitea-specific hardening step, from locking down app.ini to securing your reverse proxy.","authors":[{"term_id":1489,"user_id":65,"is_guest":0,"slug":"julia-mink","display_name":"Julia Mink","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/26ce5d4ae17d160425d842da4ea00c56716ffb5d4c58ee0cfb73de57b1de5272?s=96&d=mm&r=g","author_category":"","user_url":"","last_name":"Mink","first_name":"Julia","job_title":"","description":""}],"_links":{"self":[{"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/posts\/31887","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/users\/65"}],"replies":[{"embeddable":true,"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/comments?post=31887"}],"version-history":[{"count":4,"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/posts\/31887\/revisions"}],"predecessor-version":[{"id":31957,"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/posts\/31887\/revisions\/31957"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/media\/31951"}],"wp:attachment":[{"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/media?parent=31887"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/categories?post=31887"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/tags?post=31887"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/contabo.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=31887"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}