{"id":2896,"date":"2025-12-04T23:15:14","date_gmt":"2025-12-04T20:15:14","guid":{"rendered":"https:\/\/www.dchost.com\/blog\/running-a-vps-without-a-control-panel-over-ssh-only\/"},"modified":"2025-12-04T23:15:14","modified_gmt":"2025-12-04T20:15:14","slug":"running-a-vps-without-a-control-panel-over-ssh-only","status":"publish","type":"post","link":"https:\/\/www.dchost.com\/blog\/en\/running-a-vps-without-a-control-panel-over-ssh-only\/","title":{"rendered":"Running a VPS Without a Control Panel Over SSH Only"},"content":{"rendered":"<div class=\"dchost-blog-content-wrapper\"><p>If you are comfortable with a terminal and you want full control over your infrastructure, running a <a href=\"https:\/\/www.dchost.com\/vps\">VPS<\/a> without a control panel is often the cleanest and most efficient option. No extra daemons, no auto-generated configs you do not understand, no mystery resource usage. Just Linux, SSH and the exact services you choose. In this article, I will walk through how we at dchost.com approach SSH-only VPS setups for real projects: from first login and hardening, to configuring Nginx and PHP, to deploying websites using Git, rsync or simple file sync. The goal is not to turn you into a Linux guru overnight, but to give you a practical, reproducible checklist you can apply every time you get a new VPS. Whether you are hosting a single client site, a small Laravel or Node.js app, or a lean WordPress installation, you will see how to keep everything manageable, secure and well-documented without ever touching a hosting control panel.<\/p>\n<div id=\"toc_container\" class=\"toc_transparent no_bullets\"><p class=\"toc_title\">\u0130&ccedil;indekiler<\/p><ul class=\"toc_list\"><li><a href=\"#What_No_Control_Panel_Really_Means_on_a_VPS\"><span class=\"toc_number toc_depth_1\">1<\/span> What \u201cNo Control Panel\u201d Really Means on a VPS<\/a><\/li><li><a href=\"#Prerequisites_Skills_and_Mindset_for_SSHOnly_Hosting\"><span class=\"toc_number toc_depth_1\">2<\/span> Prerequisites: Skills and Mindset for SSH\u2011Only Hosting<\/a><ul><li><a href=\"#Core_Linux_and_SSH_skills\"><span class=\"toc_number toc_depth_2\">2.1<\/span> Core Linux and SSH skills<\/a><\/li><li><a href=\"#Networking_and_DNS_basics\"><span class=\"toc_number toc_depth_2\">2.2<\/span> Networking and DNS basics<\/a><\/li><li><a href=\"#Version_control_and_deployments\"><span class=\"toc_number toc_depth_2\">2.3<\/span> Version control and deployments<\/a><\/li><\/ul><\/li><li><a href=\"#Step_1_Initial_VPS_Setup_and_Security_Hardening\"><span class=\"toc_number toc_depth_1\">3<\/span> Step 1: Initial VPS Setup and Security Hardening<\/a><ul><li><a href=\"#1_Log_in_as_root_and_update_the_system\"><span class=\"toc_number toc_depth_2\">3.1<\/span> 1. Log in as root and update the system<\/a><\/li><li><a href=\"#2_Create_a_nonroot_sudo_user\"><span class=\"toc_number toc_depth_2\">3.2<\/span> 2. Create a non\u2011root sudo user<\/a><\/li><li><a href=\"#3_Set_up_SSH_keys_and_disable_password_logins\"><span class=\"toc_number toc_depth_2\">3.3<\/span> 3. Set up SSH keys and disable password logins<\/a><\/li><li><a href=\"#4_Configure_a_simple_firewall\"><span class=\"toc_number toc_depth_2\">3.4<\/span> 4. Configure a simple firewall<\/a><\/li><li><a href=\"#5_Add_basic_intrusion_protection\"><span class=\"toc_number toc_depth_2\">3.5<\/span> 5. Add basic intrusion protection<\/a><\/li><\/ul><\/li><li><a href=\"#Step_2_Build_a_Lean_Web_Stack_Without_a_Panel\"><span class=\"toc_number toc_depth_1\">4<\/span> Step 2: Build a Lean Web Stack Without a Panel<\/a><ul><li><a href=\"#Install_Nginx_PHP-FPM_and_MariaDB\"><span class=\"toc_number toc_depth_2\">4.1<\/span> Install Nginx, PHP-FPM and MariaDB<\/a><\/li><li><a href=\"#Secure_the_database_minimally\"><span class=\"toc_number toc_depth_2\">4.2<\/span> Secure the database minimally<\/a><\/li><li><a href=\"#Create_a_web_root_and_user-friendly_structure\"><span class=\"toc_number toc_depth_2\">4.3<\/span> Create a web root and user-friendly structure<\/a><\/li><li><a href=\"#Configure_an_Nginx_server_block_virtual_host\"><span class=\"toc_number toc_depth_2\">4.4<\/span> Configure an Nginx server block (virtual host)<\/a><\/li><\/ul><\/li><li><a href=\"#Step_3_Deploying_Websites_Over_SSH_Only\"><span class=\"toc_number toc_depth_1\">5<\/span> Step 3: Deploying Websites Over SSH Only<\/a><ul><li><a href=\"#Option_A_Simple_SFTP_or_SCP_for_small_infrequent_sites\"><span class=\"toc_number toc_depth_2\">5.1<\/span> Option A: Simple SFTP or SCP for small, infrequent sites<\/a><\/li><li><a href=\"#Option_B_rsync_over_SSH_for_repeatable_file_sync\"><span class=\"toc_number toc_depth_2\">5.2<\/span> Option B: rsync over SSH for repeatable file sync<\/a><\/li><li><a href=\"#Option_C_Git-based_deployments_push_to_your_VPS\"><span class=\"toc_number toc_depth_2\">5.3<\/span> Option C: Git-based deployments (push to your VPS)<\/a><\/li><li><a href=\"#Option_D_CICD_from_GitHub_GitLab_or_your_own_runner\"><span class=\"toc_number toc_depth_2\">5.4<\/span> Option D: CI\/CD from GitHub, GitLab or your own runner<\/a><\/li><\/ul><\/li><li><a href=\"#Step_4_Domains_HTTPS_and_Logs_Without_a_Panel\"><span class=\"toc_number toc_depth_1\">6<\/span> Step 4: Domains, HTTPS and Logs Without a Panel<\/a><ul><li><a href=\"#Point_your_domain_to_the_VPS\"><span class=\"toc_number toc_depth_2\">6.1<\/span> Point your domain to the VPS<\/a><\/li><li><a href=\"#Obtain_a_free_Lets_Encrypt_certificate_via_SSH\"><span class=\"toc_number toc_depth_2\">6.2<\/span> Obtain a free Let\u2019s Encrypt certificate via SSH<\/a><\/li><li><a href=\"#Understand_where_logs_live_and_how_to_read_them\"><span class=\"toc_number toc_depth_2\">6.3<\/span> Understand where logs live and how to read them<\/a><\/li><\/ul><\/li><li><a href=\"#Step_5_Backups_Updates_and_Ongoing_Maintenance\"><span class=\"toc_number toc_depth_1\">7<\/span> Step 5: Backups, Updates and Ongoing Maintenance<\/a><ul><li><a href=\"#Back_up_both_data_and_configuration\"><span class=\"toc_number toc_depth_2\">7.1<\/span> Back up both data and configuration<\/a><\/li><li><a href=\"#Keep_the_OS_and_packages_updated\"><span class=\"toc_number toc_depth_2\">7.2<\/span> Keep the OS and packages updated<\/a><\/li><li><a href=\"#Monitor_resource_usage_and_basic_health\"><span class=\"toc_number toc_depth_2\">7.3<\/span> Monitor resource usage and basic health<\/a><\/li><\/ul><\/li><li><a href=\"#When_a_Control_Panel_Still_Makes_Sense\"><span class=\"toc_number toc_depth_1\">8<\/span> When a Control Panel Still Makes Sense<\/a><\/li><li><a href=\"#Practical_Workflow_Tips_That_Make_SSHOnly_Hosting_Comfortable\"><span class=\"toc_number toc_depth_1\">9<\/span> Practical Workflow Tips That Make SSH\u2011Only Hosting Comfortable<\/a><ul><li><a href=\"#Standardise_your_layout_and_scripts\"><span class=\"toc_number toc_depth_2\">9.1<\/span> Standardise your layout and scripts<\/a><\/li><li><a href=\"#Use_systemd_units_for_background_jobs\"><span class=\"toc_number toc_depth_2\">9.2<\/span> Use systemd units for background jobs<\/a><\/li><li><a href=\"#Take_SSH_security_seriously_from_day_one\"><span class=\"toc_number toc_depth_2\">9.3<\/span> Take SSH security seriously from day one<\/a><\/li><\/ul><\/li><li><a href=\"#Conclusion_A_Clean_Controllable_Way_to_Run_Your_Websites\"><span class=\"toc_number toc_depth_1\">10<\/span> Conclusion: A Clean, Controllable Way to Run Your Websites<\/a><\/li><\/ul><\/div>\n<h2><span id=\"What_No_Control_Panel_Really_Means_on_a_VPS\">What \u201cNo Control Panel\u201d Really Means on a VPS<\/span><\/h2>\n<p>Let us first clarify what we mean by running a VPS without a control panel. You still have an operating system, system services and a web stack. The difference is that you install and manage everything directly over SSH instead of through cPanel, DirectAdmin or Plesk.<\/p>\n<p>In practice, this usually means:<\/p>\n<ul>\n<li>You connect via SSH to manage the server instead of using a browser-based panel.<\/li>\n<li>You install packages with your distro\u2019s package manager (for example, <code>apt<\/code> or <code>dnf<\/code>).<\/li>\n<li>You configure services (Nginx, Apache, PHP-FPM, databases) using text files under <code>\/etc<\/code>.<\/li>\n<li>You create and manage system users, SSH keys and permissions yourself.<\/li>\n<li>You handle deployments with tools like Git, rsync, SFTP or CI\/CD pipelines.<\/li>\n<\/ul>\n<p>This approach makes the most sense when you:<\/p>\n<ul>\n<li>Run a small number of sites or applications and prefer a minimal footprint.<\/li>\n<li>Care about understanding exactly what runs on your VPS.<\/li>\n<li>Want maximum flexibility for custom stacks (Node.js, Go, containers, etc.).<\/li>\n<li>Are comfortable with Linux basics and willing to document your setup.<\/li>\n<\/ul>\n<p>If you are unsure which Linux distribution to start with, I strongly recommend reading our guide on <a href='https:\/\/www.dchost.com\/blog\/en\/vps-icin-linux-dagitimi-secimi-ubuntu-debian-almalinux-ve-rocky-linux-karsilastirmasi\/'>choosing a Linux distro for your VPS<\/a>. It will help you pick a platform that matches both your habits and your long-term maintenance needs.<\/p>\n<h2><span id=\"Prerequisites_Skills_and_Mindset_for_SSHOnly_Hosting\">Prerequisites: Skills and Mindset for SSH\u2011Only Hosting<\/span><\/h2>\n<p>Before going panel-free, it helps to be honest about the skills you already have and those you need to build. You do not need to be a kernel developer, but you should be comfortable with a few fundamentals.<\/p>\n<h3><span id=\"Core_Linux_and_SSH_skills\">Core Linux and SSH skills<\/span><\/h3>\n<p>At minimum, you should know how to:<\/p>\n<ul>\n<li>Navigate directories with <code>cd<\/code>, <code>ls<\/code>, <code>pwd<\/code> and manage files with <code>cp<\/code>, <code>mv<\/code>, <code>rm<\/code>.<\/li>\n<li>Edit configuration files with <code>nano<\/code> or <code>vim<\/code>.<\/li>\n<li>Use <code>sudo<\/code> safely and understand the difference between root and a normal user.<\/li>\n<li>Generate SSH keys (<code>ssh-keygen<\/code>) and use <code>ssh<\/code>, <code>scp<\/code>, <code>sftp<\/code>.<\/li>\n<li>Start, stop and inspect services using <code>systemctl<\/code> and <code>journalctl<\/code>.<\/li>\n<\/ul>\n<h3><span id=\"Networking_and_DNS_basics\">Networking and DNS basics<\/span><\/h3>\n<p>You will also need a basic understanding of:<\/p>\n<ul>\n<li>Public IP addresses, ports (22 for SSH, 80 for HTTP, 443 for HTTPS), and firewalls.<\/li>\n<li>DNS A\/AAAA records and how to point your domain to your VPS IP.<\/li>\n<li>What an SSL\/TLS certificate is and why you need one for HTTPS.<\/li>\n<\/ul>\n<p>If DNS concepts are still fuzzy, bookmark our detailed guide to <a href='https:\/\/www.dchost.com\/blog\/en\/dns-kayitlari-adan-zye-a-aaaa-cname-mx-txt-srv-caa-ve-sizi-yakan-o-kucuk-hatalar\/'>DNS records explained from A to Z<\/a> and refer back whenever you are wiring domains to your VPS.<\/p>\n<h3><span id=\"Version_control_and_deployments\">Version control and deployments<\/span><\/h3>\n<p>You do not strictly need Git to deploy over SSH, but it makes your life much easier. Ideally you:<\/p>\n<ul>\n<li>Track your website or application code in a Git repository.<\/li>\n<li>Tag releases or at least keep a clean <code>main<\/code> \/ <code>master<\/code> branch.<\/li>\n<li>Are open to using simple deployment scripts or CI\/CD later on.<\/li>\n<\/ul>\n<h2><span id=\"Step_1_Initial_VPS_Setup_and_Security_Hardening\">Step 1: Initial VPS Setup and Security Hardening<\/span><\/h2>\n<p>Once your dchost.com VPS is provisioned and you have the root credentials, your first tasks are always the same: log in, create a non\u2011root user, lock down SSH and set up a basic firewall. A few minutes of discipline here will save you from a lot of noise and risk later.<\/p>\n<h3><span id=\"1_Log_in_as_root_and_update_the_system\">1. Log in as root and update the system<\/span><\/h3>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">ssh root@your-server-ip\n\n# On Debian\/Ubuntu\napt update &amp;&amp; apt upgrade -y\n\n# On AlmaLinux\/Rocky Linux\nyum update -y  # or dnf update -y\n<\/code><\/pre>\n<h3><span id=\"2_Create_a_nonroot_sudo_user\">2. Create a non\u2011root sudo user<\/span><\/h3>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">adduser deploy\nusermod -aG sudo deploy   # on Debian\/Ubuntu\n# or\nusermod -aG wheel deploy  # on RHEL-family\n<\/code><\/pre>\n<p>From now on, you will log in as <code>deploy<\/code> (or whatever name you choose) and only use <code>sudo<\/code> when necessary.<\/p>\n<h3><span id=\"3_Set_up_SSH_keys_and_disable_password_logins\">3. Set up SSH keys and disable password logins<\/span><\/h3>\n<p>On your local machine:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">ssh-keygen -t ed25519 -C 'your-email@example.com'\nssh-copy-id deploy@your-server-ip\n<\/code><\/pre>\n<p>Then harden SSH on the server by editing <code>\/etc\/ssh\/sshd_config<\/code>:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">PermitRootLogin no\nPasswordAuthentication no\n<\/code><\/pre>\n<p>Reload SSH:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo systemctl reload sshd<\/code><\/pre>\n<p>For a deeper dive into hardening SSH itself (hardware keys, SSH CA, key rotation) you can follow our playbook in <a href='https:\/\/www.dchost.com\/blog\/en\/vpste-ssh-guvenligi-nasil-saglamlasir-fido2-anahtarlari-ssh-ca-ve-rotasyonun-sicacik-yolculugu\/'>VPS SSH hardening without the drama<\/a>.<\/p>\n<h3><span id=\"4_Configure_a_simple_firewall\">4. Configure a simple firewall<\/span><\/h3>\n<p>On Debian\/Ubuntu, <code>ufw<\/code> is a great starting point:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo ufw default deny incoming\nsudo ufw default allow outgoing\nsudo ufw allow 22\/tcp    # SSH\nsudo ufw allow 80\/tcp    # HTTP\nsudo ufw allow 443\/tcp   # HTTPS\nsudo ufw enable\n<\/code><\/pre>\n<p>On RHEL-family distros, you can use <code>firewalld<\/code> or go more advanced later with <code>nftables<\/code>.<\/p>\n<h3><span id=\"5_Add_basic_intrusion_protection\">5. Add basic intrusion protection<\/span><\/h3>\n<p>Tools like Fail2ban watch logs for repeated failed logins and temporarily block abusive IPs. On Debian\/Ubuntu:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo apt install fail2ban -y\n<\/code><\/pre>\n<p>Use the default jail for SSH to start, and tune later as you add services.<\/p>\n<p>If you want a broader, step-by-step checklist covering firewalls, patching, intrusion detection and more, our article <a href='https:\/\/www.dchost.com\/blog\/en\/vps-sunucu-guvenligi-nasil-saglanir-kapiyi-acik-birakmadan-yasamanin-sirri\/'>how to secure a VPS server without leaving the door open<\/a> is written exactly for this phase.<\/p>\n<h2><span id=\"Step_2_Build_a_Lean_Web_Stack_Without_a_Panel\">Step 2: Build a Lean Web Stack Without a Panel<\/span><\/h2>\n<p>With a secure base, you can now install the components that actually serve your websites. I will assume a common stack:<\/p>\n<ul>\n<li>Nginx as the web server and reverse proxy<\/li>\n<li>PHP-FPM for PHP applications like WordPress and Laravel<\/li>\n<li>MariaDB or MySQL for databases (PostgreSQL is also an option)<\/li>\n<\/ul>\n<h3><span id=\"Install_Nginx_PHP-FPM_and_MariaDB\">Install Nginx, PHP-FPM and MariaDB<\/span><\/h3>\n<p>On Debian\/Ubuntu:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo apt install nginx php-fpm php-mysql mariadb-server -y\n<\/code><\/pre>\n<p>On AlmaLinux\/Rocky Linux, package names will differ slightly (for example <code>php-fpm<\/code>, <code>php-mysqlnd<\/code>, <code>mariadb-server<\/code> via <code>dnf<\/code>).<\/p>\n<p>Enable and start the services:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo systemctl enable nginx php-fpm mariadb\nsudo systemctl start nginx php-fpm mariadb\n<\/code><\/pre>\n<h3><span id=\"Secure_the_database_minimally\">Secure the database minimally<\/span><\/h3>\n<p>Run the secure installation script:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo mysql_secure_installation<\/code><\/pre>\n<p>Set a strong root password, remove anonymous users and test databases, and disable remote root login unless you have a specific reason to keep it.<\/p>\n<h3><span id=\"Create_a_web_root_and_user-friendly_structure\">Create a web root and user-friendly structure<\/span><\/h3>\n<p>A clear directory structure makes SSH-only management far easier. A common pattern:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">\/var\/www\/\n  example.com\/\n    current\/      # active release\n    releases\/     # older releases (optional, for zero-downtime)\n    shared\/       # uploads, env files, logs\n<\/code><\/pre>\n<p>Create the base directories and set permissions:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo mkdir -p \/var\/www\/example.com\/current\nsudo chown -R deploy:www-data \/var\/www\/example.com\nsudo chmod -R 750 \/var\/www\/example.com\n<\/code><\/pre>\n<p>Replace <code>www-data<\/code> with your web server user if different (on some distros it is <code>nginx<\/code>).<\/p>\n<h3><span id=\"Configure_an_Nginx_server_block_virtual_host\">Configure an Nginx server block (virtual host)<\/span><\/h3>\n<p>Create a new config file, for example <code>\/etc\/nginx\/sites-available\/example.com.conf<\/code>:<\/p>\n<pre class=\"language-nginx line-numbers\"><code class=\"language-nginx\">server {\n    listen 80;\n    server_name example.com www.example.com;\n\n    root \/var\/www\/example.com\/current\/public;\n    index index.php index.html;\n\n    access_log \/var\/log\/nginx\/example.com.access.log;\n    error_log  \/var\/log\/nginx\/example.com.error.log;\n\n    location \/ {\n        try_files $uri $uri\/ \/index.php?$query_string;\n    }\n\n    location ~ .php$ {\n        include snippets\/fastcgi-php.conf;\n        fastcgi_pass unix:\/run\/php\/php-fpm.sock;\n    }\n\n    location ~* \/.(git|env|htaccess)$ {\n        deny all;\n    }\n}\n<\/code><\/pre>\n<p>Enable the site and reload Nginx:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo ln -s \/etc\/nginx\/sites-available\/example.com.conf \/etc\/nginx\/sites-enabled\/\nsudo nginx -t\nsudo systemctl reload nginx\n<\/code><\/pre>\n<p>At this point, Nginx will serve whatever you place inside <code>\/var\/www\/example.com\/current<\/code>, even if it is just a static <code>index.html<\/code>.<\/p>\n<h2><span id=\"Step_3_Deploying_Websites_Over_SSH_Only\">Step 3: Deploying Websites Over SSH Only<\/span><\/h2>\n<p>With the web stack ready, the main question becomes: how do you get your code onto the server, and how do you update it safely? There is no control panel file manager, so your deployment flow matters a lot.<\/p>\n<h3><span id=\"Option_A_Simple_SFTP_or_SCP_for_small_infrequent_sites\">Option A: Simple SFTP or SCP for small, infrequent sites<\/span><\/h3>\n<p>For a basic static site or a rarely updated brochure site, SFTP is often enough. You can use tools like FileZilla, WinSCP or the <code>sftp<\/code> command-line client:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sftp deploy@your-server-ip\nsftp&gt; cd \/var\/www\/example.com\/current\nsftp&gt; put -r \/local\/path\/to\/site\/*\n<\/code><\/pre>\n<p>Pros: very simple, no extra setup. Cons: easy to drift from Git, easy to forget which files changed, hard to roll back quickly.<\/p>\n<h3><span id=\"Option_B_rsync_over_SSH_for_repeatable_file_sync\">Option B: rsync over SSH for repeatable file sync<\/span><\/h3>\n<p><code>rsync<\/code> is ideal when you want fast, incremental uploads and the ability to mirror your local directory to the server:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">rsync -avz --delete \n  \/local\/project\/ \n  deploy@your-server-ip:\/var\/www\/example.com\/current\/\n<\/code><\/pre>\n<p>Key flags:<\/p>\n<ul>\n<li><code>-a<\/code>: archive mode (preserves permissions, timestamps, etc.).<\/li>\n<li><code>-v<\/code>: verbose output.<\/li>\n<li><code>-z<\/code>: compress during transfer.<\/li>\n<li><code>--delete<\/code>: remove files on the server that you deleted locally.<\/li>\n<\/ul>\n<p>You can wrap this in a small shell script (for example, <code>deploy.sh<\/code>) and commit it to your repo so everyone uses the same process.<\/p>\n<h3><span id=\"Option_C_Git-based_deployments_push_to_your_VPS\">Option C: Git-based deployments (push to your VPS)<\/span><\/h3>\n<p>For anything more than a toy project, I strongly prefer Git-based deployments. The simplest pattern is:<\/p>\n<ol>\n<li>Create a bare Git repository on the VPS.<\/li>\n<li>Configure a <code>post-receive<\/code> hook that checks out the latest code to <code>current\/<\/code>.<\/li>\n<li>Push from your local machine to the VPS remote.<\/li>\n<\/ol>\n<p>On the server:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo -u deploy mkdir -p \/var\/www\/example.com\/repo.git\ncd \/var\/www\/example.com\/repo.git\nsudo -u deploy git init --bare\n<\/code><\/pre>\n<p>Create <code>hooks\/post-receive<\/code> (owned by <code>deploy<\/code>):<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">#!\/bin\/bash\nset -e\nTARGET=&quot;\/var\/www\/example.com\/current&quot;\nGIT_DIR=&quot;\/var\/www\/example.com\/repo.git&quot;\nTMP_DIR=&quot;\/var\/www\/example.com\/tmp-deploy-$$&quot;\n\nmkdir -p &quot;$TMP_DIR&quot;\nGIT_WORK_TREE=&quot;$TMP_DIR&quot; git --git-dir=&quot;$GIT_DIR&quot; checkout -f main\n\n# Run build steps here if needed (npm build, composer install, etc.)\n# For example, for a PHP app:\n# cd &quot;$TMP_DIR&quot; &amp;&amp; composer install --no-dev --optimize-autoloader\n\nrm -rf &quot;$TARGET&quot;\nmv &quot;$TMP_DIR&quot; &quot;$TARGET&quot;\n<\/code><\/pre>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo chmod +x \/var\/www\/example.com\/repo.git\/hooks\/post-receive\n<\/code><\/pre>\n<p>On your local machine, add a remote and push:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">git remote add production deploy@your-server-ip:\/var\/www\/example.com\/repo.git\ngit push production main\n<\/code><\/pre>\n<p>Each push will trigger the hook and update your site. For more sophisticated zero-downtime rollouts with symlinked releases, you can build on the patterns we share in <a href='https:\/\/www.dchost.com\/blog\/en\/vpse-sifir-kesinti-ci-cd-nasil-kurulur-rsync-sembolik-surumler-ve-systemd-ile-sicacik-bir-yolculuk\/'>our zero-downtime CI\/CD to a VPS guide<\/a>.<\/p>\n<h3><span id=\"Option_D_CICD_from_GitHub_GitLab_or_your_own_runner\">Option D: CI\/CD from GitHub, GitLab or your own runner<\/span><\/h3>\n<p>Once you are comfortable deploying manually, adding a CI\/CD pipeline is the natural next step. The general flow looks like this:<\/p>\n<ul>\n<li>On push to <code>main<\/code> or on a tagged release, your CI pipeline runs tests and builds assets.<\/li>\n<li>If everything passes, CI connects to your VPS via SSH.<\/li>\n<li>It either runs your <code>rsync<\/code> script or pushes to the bare repo, possibly with environment-specific steps.<\/li>\n<\/ul>\n<p>This keeps deployments repeatable and makes it easy for teammates to ship changes without shell access to the server.<\/p>\n<h2><span id=\"Step_4_Domains_HTTPS_and_Logs_Without_a_Panel\">Step 4: Domains, HTTPS and Logs Without a Panel<\/span><\/h2>\n<p>A control panel normally hides domain pointing, SSL and log access behind nice buttons. On an SSH-only VPS, you do the same things manually, but they are not complicated once you see the pattern.<\/p>\n<h3><span id=\"Point_your_domain_to_the_VPS\">Point your domain to the VPS<\/span><\/h3>\n<p>At your domain registrar or DNS provider, create:<\/p>\n<ul>\n<li>An A record for <code>example.com<\/code> pointing to your VPS IPv4.<\/li>\n<li>An optional AAAA record pointing to your IPv6 if your VPS has one.<\/li>\n<li>A CNAME or additional A record for <code>www.example.com<\/code> if you want it.<\/li>\n<\/ul>\n<p>After DNS propagation (often a few minutes if TTLs are low), visiting <code>http:\/\/example.com<\/code> should hit your Nginx server block.<\/p>\n<h3><span id=\"Obtain_a_free_Lets_Encrypt_certificate_via_SSH\">Obtain a free Let\u2019s Encrypt certificate via SSH<\/span><\/h3>\n<p>On Debian\/Ubuntu, the <code>certbot<\/code> package makes this easy:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo apt install certbot python3-certbot-nginx -y\nsudo certbot --nginx -d example.com -d www.example.com\n<\/code><\/pre>\n<p>Certbot will:<\/p>\n<ul>\n<li>Validate domain ownership using HTTP-01 challenge.<\/li>\n<li>Obtain a certificate.<\/li>\n<li>Update your Nginx config to use HTTPS and redirect HTTP to HTTPS.<\/li>\n<li>Install a cron job or systemd timer for auto-renewal.<\/li>\n<\/ul>\n<p>If you later need wildcards or more advanced DNS-01 flows at scale, we cover this in detail in our article about Let\u2019s Encrypt wildcard automation and DNS challenges (linked from other posts).<\/p>\n<h3><span id=\"Understand_where_logs_live_and_how_to_read_them\">Understand where logs live and how to read them<\/span><\/h3>\n<p>Without a panel, logs are your main observability tool. For a typical Nginx + PHP-FPM stack:<\/p>\n<ul>\n<li><code>\/var\/log\/nginx\/example.com.access.log<\/code> \u2013 all HTTP requests.<\/li>\n<li><code>\/var\/log\/nginx\/example.com.error.log<\/code> \u2013 Nginx and upstream errors.<\/li>\n<li><code>journalctl -u php-fpm<\/code> \u2013 PHP-FPM service logs.<\/li>\n<li><code>journalctl -u nginx<\/code> \u2013 Nginx service logs.<\/li>\n<\/ul>\n<p>Simple commands you will use a lot:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo tail -f \/var\/log\/nginx\/example.com.error.log\nsudo journalctl -u nginx -f\n<\/code><\/pre>\n<p>As your stack grows, you may want centralised log collection and alerts; we explore those patterns in various monitoring and log management guides on our blog.<\/p>\n<h2><span id=\"Step_5_Backups_Updates_and_Ongoing_Maintenance\">Step 5: Backups, Updates and Ongoing Maintenance<\/span><\/h2>\n<p>Control panels often come with built-in backup wizards, update buttons and monitoring widgets. On an SSH-only VPS, you must consciously design these routines yourself. The good news: you can make them simpler and more reliable than many default panel setups.<\/p>\n<h3><span id=\"Back_up_both_data_and_configuration\">Back up both data and configuration<\/span><\/h3>\n<p>A solid backup strategy always includes:<\/p>\n<ul>\n<li>Database backups (for example, <code>mysqldump<\/code> exports for MariaDB\/MySQL).<\/li>\n<li>Application files (code, uploads, configs). Usually your <code>\/var\/www\/<\/code> tree.<\/li>\n<li>Offsite copies (to another VPS, S3-compatible storage, or a backup service).<\/li>\n<\/ul>\n<p>Example quick-and-dirty backup script (run via cron):<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">#!\/bin\/bash\nset -e\nBACKUP_DIR=&quot;\/var\/backups\/example.com\/$(date +%F)&quot;\nmkdir -p &quot;$BACKUP_DIR&quot;\n\n# Database\nmysqldump -u root -p'STRONGPASS' exampledb &gt; &quot;$BACKUP_DIR\/db.sql&quot;\n\n# Files\nrsync -a \/var\/www\/example.com\/ &quot;$BACKUP_DIR\/www\/&quot;\n<\/code><\/pre>\n<p>For a more robust, automated approach (including storing backups on remote storage), study our article on <a href='https:\/\/www.dchost.com\/blog\/en\/3-2-1-yedekleme-stratejisi-neden-ise-yariyor-cpanel-plesk-ve-vpste-otomatik-yedekleri-nasil-kurarsin\/'>the 3\u20112\u20111 backup strategy and automating backups on a VPS<\/a>. The same principles apply perfectly to SSH-only servers.<\/p>\n<h3><span id=\"Keep_the_OS_and_packages_updated\">Keep the OS and packages updated<\/span><\/h3>\n<p>Set a recurring reminder (or cron job) to update your system:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\"># Debian\/Ubuntu\nsudo apt update &amp;&amp; sudo apt upgrade -y\n\n# AlmaLinux\/Rocky\nsudo dnf update -y\n<\/code><\/pre>\n<p>Security updates should not be postponed for months. For critical servers, you can enable unattended security upgrades, but always keep an eye on change logs and be ready to roll back in case of rare regressions.<\/p>\n<h3><span id=\"Monitor_resource_usage_and_basic_health\">Monitor resource usage and basic health<\/span><\/h3>\n<p>Even simple tools can give you a good feel for the health of your SSH-only VPS:<\/p>\n<ul>\n<li><code>top<\/code> or <code>htop<\/code> \u2013 CPU and memory usage.<\/li>\n<li><code>df -h<\/code> \u2013 disk space.<\/li>\n<li><code>free -h<\/code> \u2013 memory and swap usage.<\/li>\n<li><code>systemctl status<\/code> \u2013 check that core services are active.<\/li>\n<\/ul>\n<p>As traffic grows, consider adding proper monitoring and alerting (Prometheus, Grafana, external uptime checks) so you do not have to babysit the terminal all day.<\/p>\n<h2><span id=\"When_a_Control_Panel_Still_Makes_Sense\">When a Control Panel Still Makes Sense<\/span><\/h2>\n<p>Running everything over SSH is powerful, but it is not the right tool for every team or project. In our experience at dchost.com, a graphical control panel can still be a better fit when:<\/p>\n<ul>\n<li>You host dozens or hundreds of small sites for non-technical clients.<\/li>\n<li>You need to delegate email, DNS, FTP and database access to many different users.<\/li>\n<li>Your internal team is more comfortable with web interfaces than the terminal.<\/li>\n<li>You value the convenience of wizards for tasks like email setup and one-click installers.<\/li>\n<\/ul>\n<p>The nice part is that your choice is not permanent. You can start with an SSH-only VPS for your core applications, and later add a panel on another VPS for multi-tenant hosting, or the other way around. Our infrastructure at dchost.com is built to support both models: lean SSH-only VPS setups for developers who want full control, and panel-based hosting for agencies and businesses that need delegation and convenience.<\/p>\n<h2><span id=\"Practical_Workflow_Tips_That_Make_SSHOnly_Hosting_Comfortable\">Practical Workflow Tips That Make SSH\u2011Only Hosting Comfortable<\/span><\/h2>\n<p>Before we wrap up, here are a few patterns we see consistently working well for teams that live on SSH-only VPS servers.<\/p>\n<h3><span id=\"Standardise_your_layout_and_scripts\">Standardise your layout and scripts<\/span><\/h3>\n<p>Pick a directory layout and stick to it across all projects (for example, the <code>current\/releases\/shared<\/code> pattern). Use the same user name for deployments (for example, <code>deploy<\/code>) on all servers. Create small, well-documented scripts for common tasks:<\/p>\n<ul>\n<li><code>deploy.sh<\/code> \u2013 runs rsync or Git-based deployment.<\/li>\n<li><code>backup.sh<\/code> \u2013 dumps the database and syncs files.<\/li>\n<li><code>logs.sh<\/code> \u2013 tails the most relevant logs for that app.<\/li>\n<\/ul>\n<p>Commit these scripts into each project\u2019s repository so they live alongside your code.<\/p>\n<h3><span id=\"Use_systemd_units_for_background_jobs\">Use systemd units for background jobs<\/span><\/h3>\n<p>Instead of running ad-hoc background commands inside a <code>screen<\/code> or <code>tmux<\/code> session, define systemd services and timers. For example, to run a Laravel queue worker or a Node.js process, create a unit file under <code>\/etc\/systemd\/system\/<\/code>, enable it, and let systemd handle restarts and logs. It is cleaner, more debuggable, and easier to document.<\/p>\n<h3><span id=\"Take_SSH_security_seriously_from_day_one\">Take SSH security seriously from day one<\/span><\/h3>\n<p>SSH is your single front door in an SSH-only world. Beyond disabling passwords and root logins, consider:<\/p>\n<ul>\n<li>Using FIDO2 hardware keys for SSH authentication.<\/li>\n<li>Setting up an internal SSH certificate authority if you have many servers.<\/li>\n<li>Rotating keys regularly and revoking access promptly when people leave.<\/li>\n<\/ul>\n<p>We walk through these patterns with real examples in our detailed guide on <a href='https:\/\/www.dchost.com\/blog\/en\/vpste-ssh-guvenligi-nasil-saglamlasir-fido2-anahtarlari-ssh-ca-ve-rotasyonun-sicacik-yolculugu\/'>VPS SSH hardening without the drama<\/a>, which is worth a careful read if SSH-only is your primary access method.<\/p>\n<h2><span id=\"Conclusion_A_Clean_Controllable_Way_to_Run_Your_Websites\">Conclusion: A Clean, Controllable Way to Run Your Websites<\/span><\/h2>\n<p>Running a VPS without a control panel and deploying websites over SSH only is not about being \u201cmore hardcore\u201d than everyone else. It is about clarity. You know exactly which packages are installed, which processes listen on which ports, how your code gets onto the server and where your logs and backups live. For many developers and small teams, this simplicity is a relief compared to the opaque layers that panels sometimes add.<\/p>\n<p>The trade-off is that you must take responsibility for security, backups, monitoring and deployments. The good news is that these responsibilities are manageable once you break them into checklists: harden SSH, keep the OS updated, use Git or rsync for deployments, test your backups and practice restores. If you want a structured view of backup planning specifically, our article on <a href='https:\/\/www.dchost.com\/blog\/en\/3-2-1-yedekleme-stratejisi-neden-ise-yariyor-cpanel-plesk-ve-vpste-otomatik-yedekleri-nasil-kurarsin\/'>the 3\u20112\u20111 backup strategy on VPS<\/a> is a great next step.<\/p>\n<p>At dchost.com, our VPS, <a href=\"https:\/\/www.dchost.com\/dedicated-server\">dedicated server<\/a> and colocation services are built to support exactly this style of hosting: clean, predictable Linux machines with full root access, proper network and power redundancy, and the freedom to choose whether you ever install a control panel at all. Start with a modest VPS, apply the patterns in this article on top of our infrastructure, and you will have a fast, understandable and future-proof environment for your websites and applications.<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>If you are comfortable with a terminal and you want full control over your infrastructure, running a VPS without a control panel is often the cleanest and most efficient option. No extra daemons, no auto-generated configs you do not understand, no mystery resource usage. Just Linux, SSH and the exact services you choose. In this [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":2897,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26],"tags":[],"class_list":["post-2896","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-teknoloji"],"_links":{"self":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/posts\/2896","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/comments?post=2896"}],"version-history":[{"count":0,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/posts\/2896\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/media\/2897"}],"wp:attachment":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/media?parent=2896"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/categories?post=2896"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/tags?post=2896"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}