Preface

This guide introduces two methods to upload your local blog’s static files (the public folder) to your own server and configure a domain name.

① SFTP - the simplest approach

② Set up a Github repository on your VPS and configure hooks to update local files on the VPS

There’s no clear advantage between these two methods - choose whichever you prefer and feel comfortable with.

What you’ll need: a server (this demo uses Debian/Ubuntu), and a domain name.

SFTP Deployment

Install hexo-deployer-sftp

Install hexo-deployer-sftp. This allows you to deploy your site via SFTP and supports passwordless connections using ssh-agent.

Run the command: npm install hexo-deployer-sftp --save

Modify _config.yml Configuration

Modify the deploy option in your _config.yml file. Here’s a reference template:

deploy:
  type: sftp
  host: <host>
  user: <user>
  pass: <password>
  remotePath: [remote path]
  port: [port]
  privateKey: [path/to/privateKey]
  passphrase: [passphrase]
  agent: [path/to/agent/socket]
OptionDescriptionDefault
hostRemote host address
portPort number22
userUsername
passPassword
privateKeyPath to SSH private key
passphraseOptional passphrase for private key
agentPath to ssh socket$SSH_AUTH_SOCK
remotePathRoot directory on remote host/
forceUploadOverwrite existing filesfalse
concurrencyMaximum number of concurrent SFTP tasks100

: Enter your server’s public IP address.

: If you don’t plan to use adduser, you can simply enter root. For better security, you can create a new user and enter it in the option. Instructions for adduser can be found in the next section.

: Enter the password for your corresponding user.

privateKey: If you’ve already generated a certificate locally and uploaded the public key to the .ssh folder, and configured the sshd file to allow key-based login, you can fill in this option. If you set a password, remember to fill in [passphrase]. See the next section for details on generating local keys.

[remote path]: Create a directory on your VPS, for example /var/blog, and enter it here. You can also choose a different directory. The static files from the public folder will be stored here.

Git Deployment

Configure Local SSH Keys

To establish a connection between your local machine and the remote GitHub repository, you need to configure SSH keys locally. This allows you to push code directly to GitHub or remote git repositories. If this is your first time configuring SSH, set up git’s username and email:

$ git config --global user.name "your desired name"
$ git config --global user.email "your desired email"

Then generate your local key: $ ssh-keygen -t rsa -C "the email you just set". If you don’t need to set a password, just press Enter three times. If you do set a password, make sure to remember it.

Afterward, an id_rsa.pub file will appear in your user’s home directory. This is your generated public key, which needs to be uploaded to the .ssh folder later.

Server User Setup

Create a git user: adduser git. You can fill in the password and personal information as you wish.

Switch to the git user, create the ~/.ssh folder and ~/.ssh/authorized_keys file, and assign the appropriate permissions:

su git
mkdir ~/.ssh
vim ~/.ssh/authorized_keys

Press “i” to enter edit mode, copy the public key from the id_rsa.pub file generated locally into authorized_keys, press “esc”, then type “:wq” to save and exit. If you don’t like vim, you can use nano or other editors. The goal is to get the public key in there.

Also, make sure that pubkey authentication is set to yes in the sshd configuration file.

Next, enter the following commands to assign permissions:

chmod 600 /home/git/.ssh/authorized_keys
chmod 700 /home/git/.ssh

Then test whether you can log in to git from your local terminal without a password: ssh -v git@SERVER.

Create Github Repository

Create a repo directory under the var directory as the Git repository directory. Return to the server command line, switch to the root account, and enter: mkdir /var/repo, then assign permissions: chmod -R 755 /var/repo.

Next, create a hexo directory as the website root directory and assign permissions:

mkdir /var/hexo
chown -R git:git /var/hexo
chmod -R 755 /var/hexo
chown -R git:git /var/repo/
chown -R git:git /var/hexo/

Then create a bare git repository:

cd /var/repo
git init --bare hexo.git

We need to create a new Git hook for automatic deployment. In /var/repo/hexo.git, there’s an auto-generated hooks folder. We need to create a new hook file called post-receive inside it. Create the /var/repo/hexo.git/hooks/post-receive file with the following content:

#!/bin/bash
git --work-tree=/var/hexo --git-dir=/var/repo/hexo.git checkout -f

And modify its permissions:

chown -R git:git /var/repo/hexo.git/hooks/post-receive
chmod +x /var/repo/hexo.git/hooks/post-receive

Modify Hexo Configuration

Edit the site configuration file _config.yml, find deploy, and modify it according to this template:

deploy:
  type: git
  #Change repo to: repo: git@your_ip:/var/repo/hexo.git
  repo: git@your_ip:/var/repo/hexo.git
  branch: master

Domain Configuration

Caddy

my.domain {
    root * /var/hexo
    file_server
    encode gzip
    # Optional: configure logging
    log {
        output file /var/log/caddy/my.domain.access.log
        format common
    }
}

Simply replace my.domain with your own domain name and root * /var/hexo with your own directory.

Nginx

server {
    listen 80;
    listen [::]:80;
    server_name my.domain;
    
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name my.domain;
    
    # SSL certificate configuration - replace with actual certificate paths
    ssl_certificate /etc/ssl/certs/my.domain.crt;
    ssl_certificate_key /etc/ssl/private/my.domain.key;
    
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    
    ssl_protocols TLSv1.2 TLSv1.3;
    
    root /var/hexo;
    index index.html;
    
    access_log /var/log/nginx/my.domain.access.log;
    error_log /var/log/nginx/my.domain.error.log;
    
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
    
    location / {
        try_files $uri $uri/ =404;
        
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-XSS-Protection "1; mode=block" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header Referrer-Policy "no-referrer-when-downgrade" always;
    }
    
    error_page 404 /404.html;
    location = /404.html {
        internal;
    }
    
    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }
    
    location ~* \.(log|txt|sql)$ {
        deny all;
    }
}

Please obtain your own certificate and replace the paths in the SSL certificate configuration section with the absolute paths to your certificates.

Deploy Your Blog to Your VPS

Author

Shayne Wong

Publish Date

10 - 10 - 2025

License

Shayne Wong

Avatar
Shayne Wong

All time is no time when it is past.